Skip to content

Commit 2cddf8b

Browse files
Remove fstream usage from corehost (#111859)
Contributes to #111665 There's still fstream usage in corerun, so this alone doesn't resolve the Android build errors. --------- Co-authored-by: Elinor Fung <elfung@microsoft.com>
1 parent cf89ec4 commit 2cddf8b

File tree

5 files changed

+51
-89
lines changed

5 files changed

+51
-89
lines changed

src/native/corehost/hostmisc/pal.h

-12
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
#include <string>
88
#include <vector>
9-
#include <fstream>
109
#include <sstream>
1110
#include <iostream>
1211
#include <cstring>
@@ -118,14 +117,6 @@ namespace pal
118117
typedef wchar_t char_t;
119118
typedef std::wstring string_t;
120119
typedef std::wstringstream stringstream_t;
121-
// TODO: Agree on the correct encoding of the files: The PoR for now is to
122-
// temporarily wchar for Windows and char for Unix. Current implementation
123-
// implicitly expects the contents on both Windows and Unix as char and
124-
// converts them to wchar in code for Windows. This line should become:
125-
// typedef std::basic_ifstream<char_t> ifstream_t.
126-
typedef std::basic_ifstream<char> ifstream_t;
127-
typedef std::istreambuf_iterator<ifstream_t::char_type> istreambuf_iterator_t;
128-
typedef std::basic_istream<char> istream_t;
129120
typedef HRESULT hresult_t;
130121
typedef HMODULE dll_t;
131122
typedef FARPROC proc_t;
@@ -207,9 +198,6 @@ namespace pal
207198
typedef char char_t;
208199
typedef std::string string_t;
209200
typedef std::stringstream stringstream_t;
210-
typedef std::basic_ifstream<char> ifstream_t;
211-
typedef std::istreambuf_iterator<ifstream_t::char_type> istreambuf_iterator_t;
212-
typedef std::basic_istream<char> istream_t;
213201
typedef int hresult_t;
214202
typedef void* dll_t;
215203
typedef void* proc_t;

src/native/corehost/hostmisc/pal.unix.cpp

+5-13
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ bool get_install_location_from_file(const pal::string_t& file_path, bool& file_f
456456
{
457457
file_found = true;
458458
bool install_location_found = false;
459-
FILE* install_location_file = pal::file_open(file_path, "r");
459+
FILE* install_location_file = pal::file_open(file_path, _X("r"));
460460
if (install_location_file != nullptr)
461461
{
462462
if (!get_line_from_file(install_location_file, install_location))
@@ -819,12 +819,10 @@ pal::string_t pal::get_current_os_rid_platform()
819819
{
820820
// Read the file to get ID and VERSION_ID data that will be used
821821
// to construct the RID.
822-
std::fstream fsVersionFile;
823-
824-
fsVersionFile.open(versionFile, std::fstream::in);
822+
FILE* fsVersionFile = pal::file_open(versionFile, _X("r"));
825823

826824
// Proceed only if we were able to open the file
827-
if (fsVersionFile.good())
825+
if (fsVersionFile != nullptr)
828826
{
829827
pal::string_t line;
830828
pal::string_t strID(_X("ID="));
@@ -834,11 +832,8 @@ pal::string_t pal::get_current_os_rid_platform()
834832

835833
bool fFoundID = false, fFoundVersion = false;
836834

837-
// Read the first line
838-
std::getline(fsVersionFile, line);
839-
840835
// Loop until we are at the end of file
841-
while (!fsVersionFile.eof())
836+
while (get_line_from_file(fsVersionFile, line))
842837
{
843838
// Look for ID if we have not found it already
844839
if (!fFoundID)
@@ -872,13 +867,10 @@ pal::string_t pal::get_current_os_rid_platform()
872867
// We have everything we need to form the RID - break out of the loop.
873868
break;
874869
}
875-
876-
// Read the next line
877-
std::getline(fsVersionFile, line);
878870
}
879871

880872
// Close the file now that we are done with it.
881-
fsVersionFile.close();
873+
fclose(fsVersionFile);
882874

883875
if (fFoundID)
884876
{

src/native/corehost/json_parser.cpp

+37-54
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,9 @@
1717

1818
namespace {
1919

20-
// Try to match 0xEF 0xBB 0xBF byte sequence (no endianness here.)
21-
std::streampos get_utf8_bom_length(pal::istream_t& stream)
22-
{
23-
if (stream.eof())
24-
{
25-
return 0;
26-
}
27-
28-
auto peeked = stream.peek();
29-
if (peeked == EOF || ((peeked & 0xFF) != 0xEF))
30-
{
31-
return 0;
32-
}
33-
34-
unsigned char bytes[3];
35-
stream.read(reinterpret_cast<char*>(bytes), 3);
36-
if ((stream.gcount() < 3) || (bytes[1] != 0xBB) || (bytes[2] != 0xBF))
37-
{
38-
return 0;
39-
}
40-
41-
return 3;
42-
}
43-
4420
void get_line_column_from_offset(const char* data, uint64_t size, size_t offset, int *line, int *column)
4521
{
46-
assert(offset < size);
22+
assert(offset <= size);
4723

4824
*line = *column = 1;
4925

@@ -68,12 +44,6 @@ void get_line_column_from_offset(const char* data, uint64_t size, size_t offset,
6844

6945
} // empty namespace
7046

71-
void json_parser_t::realloc_buffer(size_t size)
72-
{
73-
m_json.resize(size + 1);
74-
m_json[size] = '\0';
75-
}
76-
7747
bool json_parser_t::parse_raw_data(char* data, int64_t size, const pal::string_t& context)
7848
{
7949
assert(data != nullptr);
@@ -115,51 +85,64 @@ bool json_parser_t::parse_file(const pal::string_t& path)
11585
{
11686
// This code assumes that the caller has checked that the file `path` exists
11787
// either within the bundle, or as a real file on disk.
118-
assert(m_bundle_data == nullptr);
88+
assert(m_data == nullptr);
11989
assert(m_bundle_location == nullptr);
12090

12191
if (bundle::info_t::is_single_file_bundle())
12292
{
12393
// Due to in-situ parsing on Linux,
12494
// * The json file is mapped as copy-on-write.
12595
// * The mapping cannot be immediately released, and will be unmapped by the json_parser destructor.
126-
m_bundle_data = bundle::info_t::config_t::map(path, m_bundle_location);
96+
m_data = bundle::info_t::config_t::map(path, m_bundle_location);
12797

128-
if (m_bundle_data != nullptr)
98+
if (m_data != nullptr)
12999
{
130-
bool result = parse_raw_data(m_bundle_data, m_bundle_location->size, path);
131-
return result;
100+
m_size = (size_t)m_bundle_location->size;
132101
}
133102
}
134103

135-
pal::ifstream_t file{ path };
136-
if (!file.good())
104+
if (m_data == nullptr)
137105
{
138-
trace::error(_X("Cannot use file stream for [%s]: %s"), path.c_str(), pal::strerror(errno).c_str());
139-
return false;
140-
}
106+
#ifdef _WIN32
107+
// We can't use in-situ parsing on Windows, as JSON data is encoded in
108+
// UTF-8 and the host expects wide strings.
109+
// We do not need copy-on-write, so read-only mapping will be enough.
110+
m_data = (char*)pal::mmap_read(path, &m_size);
111+
#else // _WIN32
112+
m_data = (char*)pal::mmap_copy_on_write(path, &m_size);
113+
#endif // _WIN32
141114

142-
auto current_pos = ::get_utf8_bom_length(file);
143-
file.seekg(0, file.end);
144-
auto stream_size = file.tellg();
145-
if (stream_size == -1)
146-
{
147-
trace::error(_X("Failed to get size of file [%s]"), path.c_str());
148-
return false;
115+
if (m_data == nullptr)
116+
{
117+
trace::error(_X("Cannot use file stream for [%s]: %s"), path.c_str(), pal::strerror(errno).c_str());
118+
return false;
119+
}
149120
}
150121

151-
file.seekg(current_pos, file.beg);
122+
char *data = m_data;
123+
size_t size = m_size;
152124

153-
realloc_buffer(static_cast<size_t>(stream_size - current_pos));
154-
file.read(m_json.data(), stream_size - current_pos);
125+
// Skip over UTF-8 BOM, if present
126+
if (size >= 3 && data[0] == 0xEF && data[1] == 0xBB && data[1] == 0xBF)
127+
{
128+
size -= 3;
129+
data += 3;
130+
}
155131

156-
return parse_raw_data(m_json.data(), m_json.size(), path);
132+
return parse_raw_data(data, size, path);
157133
}
158134

159135
json_parser_t::~json_parser_t()
160136
{
161-
if (m_bundle_data != nullptr)
137+
if (m_data != nullptr)
162138
{
163-
bundle::info_t::config_t::unmap(m_bundle_data, m_bundle_location);
139+
if (m_bundle_location != nullptr)
140+
{
141+
bundle::info_t::config_t::unmap(m_data, m_bundle_location);
142+
}
143+
else
144+
{
145+
pal::munmap((void*)m_data, m_size);
146+
}
164147
}
165148
}

src/native/corehost/json_parser.h

+8-10
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,22 @@ class json_parser_t {
4040
bool parse_file(const pal::string_t& path);
4141

4242
json_parser_t()
43-
: m_bundle_data(nullptr)
43+
: m_data(nullptr)
4444
, m_bundle_location(nullptr) {}
4545

4646
~json_parser_t();
4747

4848
private:
49-
// This is a vector of char and not pal::char_t because JSON data
50-
// parsed by this class is always encoded in UTF-8. On Windows,
51-
// where wide strings are used, m_json is kept in UTF-8, but converted
49+
char* m_data; // The memory mapped bytes of the file
50+
size_t m_size; // Size of the mapped memory
51+
52+
// On Windows, where wide strings are used, m_data is kept in UTF-8, but converted
5253
// to UTF-16 by m_document during load.
53-
std::vector<char> m_json;
5454
document_t m_document;
5555

56-
// If a json file is parsed from a single-file bundle, the following two fields represent:
57-
char* m_bundle_data; // The memory mapped bytes of the application bundle.
58-
const bundle::location_t* m_bundle_location; // Location of this json file within the bundle.
59-
60-
void realloc_buffer(size_t size);
56+
// If a json file is parsed from a single-file bundle, the following fields represents
57+
// the location of this json file within the bundle.
58+
const bundle::location_t* m_bundle_location;
6159
};
6260

6361
#endif // __JSON_PARSER_H__

src/native/corehost/test/nativehost/host_context_test.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
#include <iostream>
5+
#include <fstream>
56
#include <pal.h>
67
#include <error_codes.h>
78
#include <future>

0 commit comments

Comments
 (0)