17
17
18
18
namespace {
19
19
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
-
44
20
void get_line_column_from_offset (const char * data, uint64_t size, size_t offset, int *line, int *column)
45
21
{
46
- assert (offset < size);
22
+ assert (offset <= size);
47
23
48
24
*line = *column = 1 ;
49
25
@@ -68,12 +44,6 @@ void get_line_column_from_offset(const char* data, uint64_t size, size_t offset,
68
44
69
45
} // empty namespace
70
46
71
- void json_parser_t::realloc_buffer (size_t size)
72
- {
73
- m_json.resize (size + 1 );
74
- m_json[size] = ' \0 ' ;
75
- }
76
-
77
47
bool json_parser_t::parse_raw_data (char * data, int64_t size, const pal::string_t & context)
78
48
{
79
49
assert (data != nullptr );
@@ -115,51 +85,64 @@ bool json_parser_t::parse_file(const pal::string_t& path)
115
85
{
116
86
// This code assumes that the caller has checked that the file `path` exists
117
87
// either within the bundle, or as a real file on disk.
118
- assert (m_bundle_data == nullptr );
88
+ assert (m_data == nullptr );
119
89
assert (m_bundle_location == nullptr );
120
90
121
91
if (bundle::info_t::is_single_file_bundle ())
122
92
{
123
93
// Due to in-situ parsing on Linux,
124
94
// * The json file is mapped as copy-on-write.
125
95
// * 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);
127
97
128
- if (m_bundle_data != nullptr )
98
+ if (m_data != nullptr )
129
99
{
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 ;
132
101
}
133
102
}
134
103
135
- pal::ifstream_t file{ path };
136
- if (!file.good ())
104
+ if (m_data == nullptr )
137
105
{
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
141
114
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
+ }
149
120
}
150
121
151
- file.seekg (current_pos, file.beg );
122
+ char *data = m_data;
123
+ size_t size = m_size;
152
124
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
+ }
155
131
156
- return parse_raw_data (m_json. data (), m_json. size () , path);
132
+ return parse_raw_data (data, size, path);
157
133
}
158
134
159
135
json_parser_t ::~json_parser_t ()
160
136
{
161
- if (m_bundle_data != nullptr )
137
+ if (m_data != nullptr )
162
138
{
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
+ }
164
147
}
165
148
}
0 commit comments