docs: function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
  	if(!data) return data;
  	var opts = _opts || {};
  	if(!rels) rels = {'!id':{}};
  	if(DENSE != null && opts.dense == null) opts.dense = DENSE;
  	var s = (opts.dense ? [] : {});
  
  	var ref;
  	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
  
  	var pass = false, end = false;
  	var row, p, cf, R, C, addr, sstr, rr, cell;
  	var merges = [];
  	opts.biff = 12;
  	opts['!row'] = 0;
  
  	var ai = 0, af = false;
  
  	var arrayf = [];
  	var sharedf = {};
  	var supbooks = opts.supbooks || wb.supbooks || ([[]]);
  	supbooks.sharedf = sharedf;
  	supbooks.arrayf = arrayf;
  	supbooks.SheetNames = wb.SheetNames || wb.Sheets.map(function(x) { return x.name; });
  	if(!opts.supbooks) {
  		opts.supbooks = supbooks;
  		if(wb.Names) for(var i = 0; i < wb.Names.length; ++i) supbooks[0][i+1] = wb.Names[i];
  	}
  
  	var colinfo = [], rowinfo = [];
  	var seencol = false;
  
  	recordhopper(data, function ws_parse(val, R_n, RT) {
  		if(end) return;
  		switch(RT) {
  			case 0x0094: /* 'BrtWsDim' */
  				ref = val; break;
  			case 0x0000: /* 'BrtRowHdr' */
  				row = val;
  				if(opts.sheetRows && opts.sheetRows <= row.r) end=true;
  				rr = encode_row(R = row.r);
  				opts['!row'] = row.r;
  				if(val.hidden || val.hpt || val.level != null) {
  					if(val.hpt) val.hpx = pt2px(val.hpt);
  					rowinfo[val.r] = val;
  				}
  				break;
  
  			case 0x0002: /* 'BrtCellRk' */
  			case 0x0003: /* 'BrtCellError' */
  			case 0x0004: /* 'BrtCellBool' */
  			case 0x0005: /* 'BrtCellReal' */
  			case 0x0006: /* 'BrtCellSt' */
  			case 0x0007: /* 'BrtCellIsst' */
  			case 0x0008: /* 'BrtFmlaString' */
  			case 0x0009: /* 'BrtFmlaNum' */
  			case 0x000A: /* 'BrtFmlaBool' */
  			case 0x000B: /* 'BrtFmlaError' */
  				p = ({t:val[2]});
  				switch(val[2]) {
  					case 'n': p.v = val[1]; break;
  					case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
  					case 'b': p.v = val[1] ? true : false; break;
  					case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
  					case 'str': p.t = 's'; p.v = val[1]; break;
  				}
  				if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles);
  				C = val[0].c;
  				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
  				else s[encode_col(C) + rr] = p;
  				if(opts.cellFormula) {
  					af = false;
  					for(ai = 0; ai < arrayf.length; ++ai) {
  						var aii = arrayf[ai];
  						if(row.r >= aii[0].s.r && row.r <= aii[0].e.r)
  							if(C >= aii[0].s.c && C <= aii[0].e.c) {
  								p.F = encode_range(aii[0]); af = true;
  							}
  					}
  					if(!af && val.length > 3) p.f = val[3];
  				}
  				if(refguess.s.r > row.r) refguess.s.r = row.r;
  				if(refguess.s.c > C) refguess.s.c = C;
  				if(refguess.e.r < row.r) refguess.e.r = row.r;
  				if(refguess.e.c < C) refguess.e.c = C;
  				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
  					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
  				}
  				break;
  
  			case 0x0001: /* 'BrtCellBlank' */
  				if(!opts.sheetStubs || pass) break;
  				p = ({t:'z',v:undefined});
  				C = val[0].c;
  				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
  				else s[encode_col(C) + rr] = p;
  				if(refguess.s.r > row.r) refguess.s.r = row.r;
  				if(refguess.s.c > C) refguess.s.c = C;
  				if(refguess.e.r < row.r) refguess.e.r = row.r;
  				if(refguess.e.c < C) refguess.e.c = C;
  				break;
  
  			case 0x00B0: /* 'BrtMergeCell' */
  				merges.push(val); break;
  
  			case 0x01EE: /* 'BrtHLink' */
  				var rel = rels['!id'][val.relId];
  				if(rel) {
  					val.Target = rel.Target;
  					if(val.loc) val.Target += "#"+val.loc;
  					val.Rel = rel;
  				} else if(val.relId == '') {
  					val.Target = "#" + val.loc;
  				}
  				for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
  					if(opts.dense) {
  						if(!s[R]) s[R] = [];
  						if(!s[R][C]) s[R][C] = {t:'z',v:undefined};
  						s[R][C].l = val;
  					} else {
  						addr = encode_cell({c:C,r:R});
  						if(!s[addr]) s[addr] = {t:'z',v:undefined};
  						s[addr].l = val;
  					}
  				}
  				break;
  
  			case 0x01AA: /* 'BrtArrFmla' */
  				if(!opts.cellFormula) break;
  				arrayf.push(val);
  				cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr]));
  				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
  				cell.F = encode_range(val[0]);
  				break;
  			case 0x01AB: /* 'BrtShrFmla' */
  				if(!opts.cellFormula) break;
  				sharedf[encode_cell(val[0].s)] = val[1];
  				cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]);
  				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
  				break;
  
  			/* identical to 'ColInfo' in XLS */
  			case 0x003C: /* 'BrtColInfo' */
  				if(!opts.cellStyles) break;
  				while(val.e >= val.s) {
  					colinfo[val.e--] = { width: val.w/256, hidden: !!(val.flags & 0x01) };
  					if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
  					process_col(colinfo[val.e+1]);
  				}
  				break;
  
  			case 0x00A1: /* 'BrtBeginAFilter' */
  				s['!autofilter'] = { ref:encode_range(val) };
  				break;
  
  			case 0x01DC: /* 'BrtMargins' */
  				s['!margins'] = val;
  				break;
  
  			case 0x0093: /* 'BrtWsProp' */
  				if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
  				if(val.name) wb.Sheets[idx].CodeName = val.name;
  				break;
  
  			case 0x0089: /* 'BrtBeginWsView' */
  				if(!wb.Views) wb.Views = [{}];
  				if(!wb.Views[0]) wb.Views[0] = {};
  				if(val.RTL) wb.Views[0].RTL = true;
  				break;
  
  			case 0x01E5: /* 'BrtWsFmtInfo' */
  				break;
  			case 0x00AF: /* 'BrtAFilterDateGroupItem' */
  			case 0x0284: /* 'BrtActiveX' */
  			case 0x0271: /* 'BrtBigName' */
  			case 0x0232: /* 'BrtBkHim' */
  			case 0x018C: /* 'BrtBrk' */
  			case 0x0458: /* 'BrtCFIcon' */
  			case 0x047A: /* 'BrtCFRuleExt' */
  			case 0x01D7: /* 'BrtCFVO' */
  			case 0x041A: /* 'BrtCFVO14' */
  			case 0x0289: /* 'BrtCellIgnoreEC' */
  			case 0x0451: /* 'BrtCellIgnoreEC14' */
  			case 0x0031: /* 'BrtCellMeta' */
  			case 0x024D: /* 'BrtCellSmartTagProperty' */
  			case 0x025F: /* 'BrtCellWatch' */
  			case 0x0234: /* 'BrtColor' */
  			case 0x041F: /* 'BrtColor14' */
  			case 0x00A8: /* 'BrtColorFilter' */
  			case 0x00AE: /* 'BrtCustomFilter' */
  			case 0x049C: /* 'BrtCustomFilter14' */
  			case 0x01F3: /* 'BrtDRef' */
  			case 0x0040: /* 'BrtDVal' */
  			case 0x041D: /* 'BrtDVal14' */
  			case 0x0226: /* 'BrtDrawing' */
  			case 0x00AB: /* 'BrtDynamicFilter' */
  			case 0x00A7: /* 'BrtFilter' */
  			case 0x0499: /* 'BrtFilter14' */
  			case 0x00A9: /* 'BrtIconFilter' */
  			case 0x049D: /* 'BrtIconFilter14' */
  			case 0x0227: /* 'BrtLegacyDrawing' */
  			case 0x0228: /* 'BrtLegacyDrawingHF' */
  			case 0x0295: /* 'BrtListPart' */
  			case 0x027F: /* 'BrtOleObject' */
  			case 0x01DE: /* 'BrtPageSetup' */
  			case 0x0097: /* 'BrtPane' */
  			case 0x0219: /* 'BrtPhoneticInfo' */
  			case 0x01DD: /* 'BrtPrintOptions' */
  			case 0x0218: /* 'BrtRangeProtection' */
  			case 0x044F: /* 'BrtRangeProtection14' */
  			case 0x02A8: /* 'BrtRangeProtectionIso' */
  			case 0x0450: /* 'BrtRangeProtectionIso14' */
  			case 0x0400: /* 'BrtRwDescent' */
  			case 0x0098: /* 'BrtSel' */
  			case 0x0297: /* 'BrtSheetCalcProp' */
  			case 0x0217: /* 'BrtSheetProtection' */
  			case 0x02A6: /* 'BrtSheetProtectionIso' */
  			case 0x01F8: /* 'BrtSlc' */
  			case 0x0413: /* 'BrtSparkline' */
  			case 0x01AC: /* 'BrtTable' */
  			case 0x00AA: /* 'BrtTop10Filter' */
  			case 0x0C00: /* 'BrtUid' */
  			case 0x0032: /* 'BrtValueMeta' */
  			case 0x0816: /* 'BrtWebExtension' */
  			case 0x0415: /* 'BrtWsFmtInfoEx14' */
  				break;
  
  			case 0x0023: /* 'BrtFRTBegin' */
  				pass = true; break;
  			case 0x0024: /* 'BrtFRTEnd' */
  				pass = false; break;
  			case 0x0025: /* 'BrtACBegin' */ break;
  			case 0x0026: /* 'BrtACEnd' */ break;
  
  			default:
  				if((R_n||"").indexOf("Begin") > 0){/* empty */}
  				else if((R_n||"").indexOf("End") > 0){/* empty */}
  				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
  		}
  	}, opts);
  
  	delete opts.supbooks;
  	delete opts['!row'];
  
  	if(!s["!ref"] && (refguess.s.r < 2000000 || ref && (ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0))) s["!ref"] = encode_range(ref || refguess);
  	if(opts.sheetRows && s["!ref"]) {
  		var tmpref = safe_decode_range(s["!ref"]);
  		if(opts.sheetRows <= +tmpref.e.r) {
  			tmpref.e.r = opts.sheetRows - 1;
  			if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
  			if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
  			if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
  			if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
  			s["!fullref"] = s["!ref"];
  			s["!ref"] = encode_range(tmpref);
  		}
  	}
  	if(merges.length > 0) s["!merges"] = merges;
  	if(colinfo.length > 0) s["!cols"] = colinfo;
  	if(rowinfo.length > 0) s["!rows"] = rowinfo;
  	return s;
  }