55 */ 
66
77addToLibrary ( { 
8+   $wasmFS$JSMemoryRanges : { } , 
9+ 
810  // Fetch backend: On first access of the file (either a read or a getSize), it 
911  // will fetch() the data from the network asynchronously. Otherwise, after 
1012  // that fetch it behaves just like JSFile (and it reuses the code from there). 
1113
1214  _wasmfs_create_fetch_backend_js__deps : [ 
1315    '$wasmFS$backends' , 
14-     '$wasmFS$JSMemoryFiles ' , 
15-     '_wasmfs_create_js_file_backend_js ' , 
16-     '_wasmfs_fetch_get_file_path ' , 
16+     '$wasmFS$JSMemoryRanges ' , 
17+     '_wasmfs_fetch_get_file_url ' , 
18+     '_wasmfs_fetch_get_chunk_size ' , 
1719  ] , 
1820  _wasmfs_create_fetch_backend_js : async  function ( backend )  { 
1921    // Get a promise that fetches the data and stores it in JS memory (if it has 
2022    // not already been fetched). 
21-     async  function  getFile ( file )  { 
22-       if  ( wasmFS$JSMemoryFiles [ file ] )  { 
23-         // The data is already here, so nothing to do before we continue on to 
24-         // the actual read below. 
25-         return  Promise . resolve ( ) ; 
26-       } 
27-       // This is the first time we want the file's data. 
23+     async  function  getFileRange ( file ,  offset ,  len )  { 
2824      var  url  =  '' ; 
29-       var  fileUrl_p  =  __wasmfs_fetch_get_file_path ( file ) ; 
25+       var  fileUrl_p  =  __wasmfs_fetch_get_file_url ( file ) ; 
3026      var  fileUrl  =  UTF8ToString ( fileUrl_p ) ; 
3127      var  isAbs  =  fileUrl . indexOf ( '://' )  !==  - 1 ; 
3228      if  ( isAbs )  { 
@@ -38,31 +34,71 @@ addToLibrary({
3834        }  catch  ( e )  { 
3935        } 
4036      } 
41-       var  response  =  await  fetch ( url ) ; 
37+       var  chunkSize  =  __wasmfs_fetch_get_chunk_size ( file ) ; 
38+       offset  =  offset  ||  0 ; 
39+       len  =  len  ||  chunkSize ; 
40+       var  firstChunk  =  ( offset  /  chunkSize )  |  0 ; 
41+       var  lastChunk  =  ( ( offset + len )  /  chunkSize )  |  0 ; 
42+       if  ( ! ( file  in  wasmFS$JSMemoryRanges ) )  { 
43+         var  fileInfo  =  await  fetch ( url , { method :"HEAD" ,  headers :{ "Range" : "bytes=0-" } } ) ; 
44+         if ( fileInfo . ok  && 
45+            fileInfo . headers . has ( "Content-Length" )  && 
46+            fileInfo . headers . get ( "Accept-Ranges" )  ==  "bytes"  && 
47+            ( parseInt ( fileInfo . headers . get ( "Content-Length" ) )  >  chunkSize * 2 ) )  { 
48+           wasmFS$JSMemoryRanges [ file ]  =  { size :parseInt ( fileInfo . headers . get ( "Content-Length" ) ) ,  chunks :[ ] ,  chunkSize :chunkSize } ; 
49+         }  else  { 
50+           // may as well/forced to download the whole file 
51+           var  wholeFileReq  =  await  fetch ( url ) ; 
52+           if ( ! wholeFileReq . ok )  { 
53+             throw  wholeFileReq ; 
54+           } 
55+           var  wholeFileData  =  new  Uint8Array ( await  wholeFileReq . arrayBuffer ( ) ) ; 
56+           var  text  =  new  TextDecoder ( ) . decode ( wholeFileData ) ; 
57+           wasmFS$JSMemoryRanges [ file ]  =  { size :wholeFileData . byteLength ,  chunks :[ wholeFileData ] ,  chunkSize :wholeFileData . byteLength } ; 
58+           return  Promise . resolve ( ) ; 
59+         } 
60+       } 
61+       var  allPresent  =  true ; 
62+       var  i ; 
63+       if ( lastChunk  *  chunkSize  <  offset + len )  { 
64+         lastChunk  +=  1 ; 
65+       } 
66+       for ( i  =  firstChunk ;  i  <  lastChunk ;  i ++ )  { 
67+         if ( ! wasmFS$JSMemoryRanges [ file ] . chunks [ i ] )  { 
68+           allPresent  =  false ; 
69+           break ; 
70+         } 
71+       } 
72+       if  ( allPresent )  { 
73+         // The data is already here, so nothing to do before we continue on to 
74+         // the actual read. 
75+         return  Promise . resolve ( ) ; 
76+       } 
77+       // This is the first time we want the chunk's data. 
78+       var  start  =  firstChunk * chunkSize ; 
79+       var  end  =  lastChunk * chunkSize ; 
80+       var  response  =  await  fetch ( url ,  { headers :{ "Range" : `bytes=${ start }  -${ end - 1 }  ` } } ) ; 
4281      if  ( response . ok )  { 
43-         var  buffer  =  await  response [ 'arrayBuffer' ] ( ) ; 
44-         wasmFS$JSMemoryFiles [ file ]  =  new  Uint8Array ( buffer ) ; 
82+         var  bytes  =  new  Uint8Array ( await  response [ 'arrayBuffer' ] ( ) ) ; 
83+         for  ( i  =  firstChunk ;  i  <  lastChunk ;  i ++ )  { 
84+           wasmFS$JSMemoryRanges [ file ] . chunks [ i ]  =  bytes . slice ( i * chunkSize - start , ( i + 1 ) * chunkSize - start ) ; 
85+         } 
4586      }  else  { 
4687        throw  response ; 
4788      } 
89+       return  Promise . resolve ( ) ; 
4890    } 
4991
50-     // Start with the normal JSFile operations. This sets 
51-     //   wasmFS$backends[backend] 
52-     // which we will then augment. 
53-     __wasmfs_create_js_file_backend_js ( backend ) ; 
54- 
55-     // Add the async operations on top. 
56-     var  jsFileOps  =  wasmFS$backends [ backend ] ; 
5792    wasmFS$backends [ backend ]  =  { 
5893      // alloc/free operations are not actually async. Just forward to the 
5994      // parent class, but we must return a Promise as the caller expects. 
6095      allocFile : async  ( file )  =>  { 
61-         jsFileOps . allocFile ( file ) ; 
96+         // nop 
6297        return  Promise . resolve ( ) ; 
6398      } , 
6499      freeFile : async  ( file )  =>  { 
65-         jsFileOps . freeFile ( file ) ; 
100+         // free memory 
101+         wasmFS$JSMemoryRanges [ file ]  =  undefined ; 
66102        return  Promise . resolve ( ) ; 
67103      } , 
68104
@@ -73,17 +109,39 @@ addToLibrary({
73109      // read/getSize fetch the data, then forward to the parent class. 
74110      read : async  ( file ,  buffer ,  length ,  offset )  =>  { 
75111        try  { 
76-           await  getFile ( file ) ; 
112+           await  getFileRange ( file ,   offset   ||   0 ,   length ) ; 
77113        }  catch  ( response )  { 
78114          return  response . status  ===  404  ? - { { {  cDefs . ENOENT  } } }  : - { { {  cDefs. EBADF  } } } ; 
79115        } 
80-         return  jsFileOps . read ( file,  buffer,  length,  offset) ; 
116+         var  fileInfo  =  wasmFS$JSMemoryRanges [ file ] ; 
117+         var  fileData  =  fileInfo . chunks ; 
118+         var  chunkSize  =  fileInfo . chunkSize ; 
119+         var  firstChunk  =  ( offset  /  chunkSize )  |  0 ; 
120+         var  lastChunk  =  ( ( offset + length )  /  chunkSize )  |  0 ; 
121+         if ( offset  +  length  >  lastChunk  *  chunkSize )  { 
122+           lastChunk  +=  1 ; 
123+         } 
124+         var  readLength  =  0 ; 
125+         for  ( var  i  =  firstChunk ;  i  <  lastChunk ;  i ++ )  { 
126+           var  chunk =  fileData [ i ] ; 
127+           var  start  =  Math . max ( i * chunkSize ,  offset ) ; 
128+           if ( ! chunk )  { 
129+             throw  [ fileData . length ,  firstChunk ,  lastChunk ,  i ] ; 
130+           } 
131+           var  chunkStart  =  i * chunkSize ; 
132+           var  end  =  Math . min ( chunkStart + chunkSize ,  offset + length ) ; 
133+           HEAPU8 . set ( chunk . subarray ( start - chunkStart ,  end - chunkStart ) ,  buffer + ( start - offset ) ) ; 
134+           readLength  =  end  -  offset ; 
135+         } 
136+         return  readLength ; 
81137      } , 
82138      getSize : async  ( file )  =>  { 
83139        try  { 
84-           await  getFile ( file ) ; 
85-         }  catch  ( response )  { } 
86-         return  jsFileOps . getSize ( file ) ; 
140+           await  getFileRange ( file ,  0 ,  0 ) ; 
141+         }  catch  ( response )  { 
142+           return  0 ; 
143+         } 
144+         return  wasmFS$JSMemoryRanges [ file ] . size ; 
87145      } , 
88146    } ; 
89147  } , 
0 commit comments