docs: function parse_local_file(blob, csz, usz, o, EF) {
  	/* [local file header] */
  	blob.l += 2;
  	var flags = blob.read_shift(2);
  	var meth = blob.read_shift(2);
  	var date = parse_dos_date(blob);
  
  	if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
  	var crc32 = blob.read_shift(4);
  	var _csz = blob.read_shift(4);
  	var _usz = blob.read_shift(4);
  
  	var namelen = blob.read_shift(2);
  	var efsz = blob.read_shift(2);
  
  	// TODO: flags & (1<<11) // UTF8
  	var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
  	if(efsz) {
  		var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
  		if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
  		if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
  	}
  	blob.l += efsz;
  
  	/* [encryption header] */
  
  	/* [file data] */
  	var data = blob.slice(blob.l, blob.l + _csz);
  	switch(meth) {
  		case 8: data = _inflateRawSync(blob, _usz); break;
  		case 0: break;
  		default: throw new Error("Unsupported ZIP Compression method " + meth);
  	}
  
  	/* [data descriptor] */
  	var wrn = false;
  	if(flags & 8) {
  		crc32 = blob.read_shift(4);
  		if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
  		_csz = blob.read_shift(4);
  		_usz = blob.read_shift(4);
  	}
  
  	if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
  	if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
  	var _crc32 = CRC32.buf(data, 0);
  	if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
  	cfb_add(o, name, data, {unsafe: true, mt: date});
  }