1717
1818namespace  {
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- 
4420void  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- 
7747bool  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" 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]" c_str ());
148-         return  false ;
115+         if  (m_data == nullptr )
116+         {
117+             trace::error (_X (" Cannot use file stream for [%s]: %s" 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
159135json_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}
0 commit comments