forked from sheetjs/sheetjs
		
	outline minutiae
- column levels (fixes #1655) - XLSX parse sheetPr with children (fixes #1798) - XLSX enforce 32768 string limit (fixes #1537)
This commit is contained in:
		
							parent
							
								
									4518cc8967
								
							
						
					
					
						commit
						a4ee0ef05a
					
				| @ -223,7 +223,7 @@ function write_WriteAccess(s/*:string*/, opts) { | ||||
| /* [MS-XLS] 2.4.351 */ | ||||
| function parse_WsBool(blob, length, opts) { | ||||
| 	var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0); | ||||
| 	return { fDialog: flags & 0x10 }; | ||||
| 	return { fDialog: flags & 0x10, fBelow: flags & 0x40, fRight: flags & 0x80 }; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.4.28 */ | ||||
|  | ||||
| @ -45,6 +45,7 @@ function col_obj_w(C/*:number*/, col) { | ||||
| 	if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; } | ||||
| 	else if(col.width != null) p.width = col.width; | ||||
| 	if(col.hidden) p.hidden = true; | ||||
| 	if(col.level != null) { p.outlineLevel = p.level = col.level; } | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -10,6 +10,7 @@ var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g; | ||||
| var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g; | ||||
| var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g; | ||||
| var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/; | ||||
| var sheetprregex2= /<(?:\w:)?sheetPr[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetPr)>/; | ||||
| var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/; | ||||
| 
 | ||||
| /* 18.3 Worksheets */ | ||||
| @ -32,6 +33,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro | ||||
| 	/* 18.3.1.82 sheetPr CT_SheetPr */ | ||||
| 	var sheetPr = data1.match(sheetprregex); | ||||
| 	if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx); | ||||
| 	else if((sheetPr = data1.match(sheetprregex2))) parse_ws_xml_sheetpr2(sheetPr[0], sheetPr[1]||"", s, wb, idx, styles, themes); | ||||
| 
 | ||||
| 	/* 18.3.1.35 dimension CT_SheetDimension */ | ||||
| 	var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index; | ||||
| @ -104,6 +106,9 @@ function parse_ws_xml_sheetpr(sheetPr/*:string*/, s, wb/*:WBWBProps*/, idx/*:num | ||||
| 	if(!wb.Sheets[idx]) wb.Sheets[idx] = {}; | ||||
| 	if(data.codeName) wb.Sheets[idx].CodeName = unescapexml(utf8read(data.codeName)); | ||||
| } | ||||
| function parse_ws_xml_sheetpr2(sheetPr/*:string*/, body/*:string*/, s, wb/*:WBWBProps*/, idx/*:number*/, styles, themes) { | ||||
| 	parse_ws_xml_sheetpr(sheetPr.slice(0, sheetPr.indexOf(">")), s, wb, idx); | ||||
| } | ||||
| function write_ws_xml_sheetpr(ws, wb, idx, opts, o) { | ||||
| 	var needed = false; | ||||
| 	var props = {}, payload = null; | ||||
| @ -191,6 +196,7 @@ function parse_ws_xml_cols(columns, cols) { | ||||
| 		var coll = parsexmltag(cols[coli], true); | ||||
| 		if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden); | ||||
| 		var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1; | ||||
| 		if(coll.outlineLevel) coll.level = (+coll.outlineLevel || 0); | ||||
| 		delete coll.min; delete coll.max; coll.width = +coll.width; | ||||
| 		if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); } | ||||
| 		process_col(coll); | ||||
| @ -280,6 +286,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string | ||||
| 		case 'e': o.t = "e"; break; | ||||
| 		case 'z': break; | ||||
| 		default: if(cell.v == null) { delete cell.t; break; } | ||||
| 			if(cell.v.length > 32767) throw new Error("Text length must not exceed 32767 characters"); | ||||
| 			if(opts && opts.bookSST) { | ||||
| 				v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings)); | ||||
| 				o.t = "s"; break; | ||||
|  | ||||
| @ -79,14 +79,23 @@ function parse_BrtWsFmtInfo(/*::data, length*/) { | ||||
| /* [MS-XLSB] 2.4.823 BrtWsProp */ | ||||
| function parse_BrtWsProp(data, length) { | ||||
| 	var z = {}; | ||||
| 	var f = data[data.l]; ++data.l; | ||||
| 	z.above = !(f & 0x40); | ||||
| 	z.left  = !(f & 0x80); | ||||
| 	/* TODO: pull flags */ | ||||
| 	data.l += 19; | ||||
| 	data.l += 18; | ||||
| 	z.name = parse_XLSBCodeName(data, length - 19); | ||||
| 	return z; | ||||
| } | ||||
| function write_BrtWsProp(str, o) { | ||||
| function write_BrtWsProp(str, outl, o) { | ||||
| 	if(o == null) o = new_buf(84+4*str.length); | ||||
| 	for(var i = 0; i < 3; ++i) o.write_shift(1,0); | ||||
| 	var f = 0xC0; | ||||
| 	if(outl) { | ||||
| 		if(outl.above) f &= ~0x40; | ||||
| 		if(outl.left)  f &= ~0x80; | ||||
| 	} | ||||
| 	o.write_shift(1, f); | ||||
| 	for(var i = 1; i < 3; ++i) o.write_shift(1,0); | ||||
| 	write_BrtColor({auto:1}, o); | ||||
| 	o.write_shift(-4,-1); | ||||
| 	o.write_shift(-4,-1); | ||||
| @ -660,6 +669,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ | ||||
| 			case 0x0093: /* 'BrtWsProp' */ | ||||
| 				if(!wb.Sheets[idx]) wb.Sheets[idx] = {}; | ||||
| 				if(val.name) wb.Sheets[idx].CodeName = val.name; | ||||
| 				if(val.above || val.left) s['!outline'] = { above: val.above, left: val.left }; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 0x0089: /* 'BrtBeginWsView' */ | ||||
| @ -956,7 +966,7 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) { | ||||
| 	/* passed back to write_zip and removed there */ | ||||
| 	ws['!comments'] = []; | ||||
| 	write_record(ba, "BrtBeginSheet"); | ||||
| 	if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c)); | ||||
| 	if(wb.vbaraw || ws['!outline']) write_record(ba, "BrtWsProp", write_BrtWsProp(c, ws['!outline'])); | ||||
| 	write_record(ba, "BrtWsDim", write_BrtWsDim(r)); | ||||
| 	write_WSVIEWS2(ba, ws, wb.Workbook); | ||||
| 	write_WSFMTINFO(ba, ws); | ||||
|  | ||||
| @ -618,6 +618,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 
 | ||||
| 					case 'unsynced' /*case 'Unsynced'*/: break; | ||||
| 					case 'print' /*case 'Print'*/: break; | ||||
| 					case 'printerrors' /*case 'PrintErrors'*/: break; | ||||
| 					case 'panes' /*case 'Panes'*/: break; | ||||
| 					case 'scale' /*case 'Scale'*/: break; | ||||
| 					case 'pane' /*case 'Pane'*/: break; | ||||
| @ -657,11 +658,17 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 					case 'allowformatcells' /*case 'AllowFormatCells'*/: break; | ||||
| 					case 'allowsizecols' /*case 'AllowSizeCols'*/: break; | ||||
| 					case 'allowsizerows' /*case 'AllowSizeRows'*/: break; | ||||
| 					case 'nosummaryrowsbelowdetail' /*case 'NoSummaryRowsBelowDetail'*/: break; | ||||
| 					case 'nosummaryrowsbelowdetail' /*case 'NoSummaryRowsBelowDetail'*/: | ||||
| 						if(!cursheet["!outline"]) cursheet["!outline"] = {}; | ||||
| 						cursheet["!outline"].above = true; | ||||
| 						break; | ||||
| 					case 'tabcolorindex' /*case 'TabColorIndex'*/: break; | ||||
| 					case 'donotdisplayheadings' /*case 'DoNotDisplayHeadings'*/: break; | ||||
| 					case 'showpagelayoutzoom' /*case 'ShowPageLayoutZoom'*/: break; | ||||
| 					case 'nosummarycolumnsrightdetail' /*case 'NoSummaryColumnsRightDetail'*/: break; | ||||
| 					case 'nosummarycolumnsrightdetail' /*case 'NoSummaryColumnsRightDetail'*/: | ||||
| 						if(!cursheet["!outline"]) cursheet["!outline"] = {}; | ||||
| 						cursheet["!outline"].left = true; | ||||
| 						break; | ||||
| 					case 'blackandwhite' /*case 'BlackAndWhite'*/: break; | ||||
| 					case 'donotdisplayzeros' /*case 'DoNotDisplayZeros'*/: break; | ||||
| 					case 'displaypagebreak' /*case 'DisplayPageBreak'*/: break; | ||||
|  | ||||
| @ -272,6 +272,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'ForceFullCalculation': wb.opts.FullCalc = val; break; | ||||
| 				case 'WsBool': | ||||
| 					if(val.fDialog) out["!type"] = "dialog"; | ||||
| 					if(!val.fBelow) (out["!outline"] || (out["!outline"] = {})).above = true; | ||||
| 					if(!val.fRight) (out["!outline"] || (out["!outline"] = {})).left = true; | ||||
| 					break; // TODO
 | ||||
| 				case 'XF': | ||||
| 					XFs.push(val); break; | ||||
|  | ||||
| @ -13,7 +13,7 @@ In the browser, just add a script tag: | ||||
| |-----------:|:-------------------------------------------| | ||||
| |    `unpkg` | <https://unpkg.com/xlsx/>                  | | ||||
| | `jsDelivr` | <https://jsdelivr.com/package/npm/xlsx>    | | ||||
| |    `CDNjs` | <https://cdnjs.com/libraries/xlsx>          | | ||||
| |    `CDNjs` | <https://cdnjs.com/libraries/xlsx>         | | ||||
| |    `packd` | <https://bundle.run/xlsx@latest?name=XLSX> | | ||||
| 
 | ||||
| `unpkg` makes the latest version available at: | ||||
|  | ||||
| @ -14,6 +14,7 @@ type ColInfo = { | ||||
|   wch?:    number;  // width in characters | ||||
| 
 | ||||
|   /* other fields for preserving features from files */ | ||||
|   level?:  number;  // 0-indexed outline / group level | ||||
|   MDW?:    number;  // Excel's "Max Digit Width" unit, always integral | ||||
| }; | ||||
| ``` | ||||
|  | ||||
							
								
								
									
										3
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -340,6 +340,9 @@ export interface ColInfo { | ||||
|     /** width in "characters" */ | ||||
|     wch?: number; | ||||
| 
 | ||||
|     /** outline / group level */ | ||||
|     level?: number; | ||||
| 
 | ||||
|     /** Excel's "Max Digit Width" unit, always integral */ | ||||
|     MDW?: number; | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user