forked from sheetjs/sheetjs
		
	- xlsx bin script takes `-8, --xls` options for writing BIFF8 - updated CFB to 0.12.1, CRC32 to 1.1.1 - test file spelling error (h/t @jsoref) - minified script renames write_shift / read_shift - UTF8 and XML entity processing Issues: - fixes #815 h/t @Neroth - fixes #739 h/t @LittleBreak @PWDream - fixes #553 h/t @keyiis - fixes #492 h/t @FlyingSailor @simonchan2013
		
			
				
	
	
		
			236 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* 18.4.1 charset to codepage mapping */
 | 
						|
var CS2CP = ({
 | 
						|
	/*::[*/0/*::]*/:    1252, /* ANSI */
 | 
						|
	/*::[*/1/*::]*/:   65001, /* DEFAULT */
 | 
						|
	/*::[*/2/*::]*/:   65001, /* SYMBOL */
 | 
						|
	/*::[*/77/*::]*/:  10000, /* MAC */
 | 
						|
	/*::[*/128/*::]*/:   932, /* SHIFTJIS */
 | 
						|
	/*::[*/129/*::]*/:   949, /* HANGUL */
 | 
						|
	/*::[*/130/*::]*/:  1361, /* JOHAB */
 | 
						|
	/*::[*/134/*::]*/:   936, /* GB2312 */
 | 
						|
	/*::[*/136/*::]*/:   950, /* CHINESEBIG5 */
 | 
						|
	/*::[*/161/*::]*/:  1253, /* GREEK */
 | 
						|
	/*::[*/162/*::]*/:  1254, /* TURKISH */
 | 
						|
	/*::[*/163/*::]*/:  1258, /* VIETNAMESE */
 | 
						|
	/*::[*/177/*::]*/:  1255, /* HEBREW */
 | 
						|
	/*::[*/178/*::]*/:  1256, /* ARABIC */
 | 
						|
	/*::[*/186/*::]*/:  1257, /* BALTIC */
 | 
						|
	/*::[*/204/*::]*/:  1251, /* RUSSIAN */
 | 
						|
	/*::[*/222/*::]*/:   874, /* THAI */
 | 
						|
	/*::[*/238/*::]*/:  1250, /* EASTEUROPE */
 | 
						|
	/*::[*/255/*::]*/:  1252, /* OEM */
 | 
						|
	/*::[*/69/*::]*/:   6969  /* MISC */
 | 
						|
}/*:any*/);
 | 
						|
 | 
						|
/* Parse a list of <r> tags */
 | 
						|
var parse_rs = (function parse_rs_factory() {
 | 
						|
	var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g;
 | 
						|
	/* 18.4.7 rPr CT_RPrElt */
 | 
						|
	var parse_rpr = function parse_rpr(rpr, intro, outro) {
 | 
						|
		var font = {}, cp = 65001, align = "";
 | 
						|
		var m = rpr.match(tagregex), i = 0;
 | 
						|
		if(m) for(;i!=m.length; ++i) {
 | 
						|
			var y = parsexmltag(m[i]);
 | 
						|
			switch(y[0].replace(/\w*:/g,"")) {
 | 
						|
				/* 18.8.12 condense CT_BooleanProperty */
 | 
						|
				/* ** not required . */
 | 
						|
				case '<condense': break;
 | 
						|
				/* 18.8.17 extend CT_BooleanProperty */
 | 
						|
				/* ** not required . */
 | 
						|
				case '<extend': break;
 | 
						|
				/* 18.8.36 shadow CT_BooleanProperty */
 | 
						|
				/* ** not required . */
 | 
						|
				case '<shadow':
 | 
						|
					if(!y.val) break;
 | 
						|
					/* falls through */
 | 
						|
				case '<shadow>':
 | 
						|
				case '<shadow/>': font.shadow = 1; break;
 | 
						|
				case '</shadow>': break;
 | 
						|
 | 
						|
				/* 18.4.1 charset CT_IntProperty TODO */
 | 
						|
				case '<charset':
 | 
						|
					if(y.val == '1') break;
 | 
						|
					cp = CS2CP[parseInt(y.val, 10)];
 | 
						|
					break;
 | 
						|
 | 
						|
				/* 18.4.2 outline CT_BooleanProperty TODO */
 | 
						|
				case '<outline':
 | 
						|
					if(!y.val) break;
 | 
						|
					/* falls through */
 | 
						|
				case '<outline>':
 | 
						|
				case '<outline/>': font.outline = 1; break;
 | 
						|
				case '</outline>': break;
 | 
						|
 | 
						|
				/* 18.4.5 rFont CT_FontName */
 | 
						|
				case '<rFont': font.name = y.val; break;
 | 
						|
 | 
						|
				/* 18.4.11 sz CT_FontSize */
 | 
						|
				case '<sz': font.sz = y.val; break;
 | 
						|
 | 
						|
				/* 18.4.10 strike CT_BooleanProperty */
 | 
						|
				case '<strike':
 | 
						|
					if(!y.val) break;
 | 
						|
					/* falls through */
 | 
						|
				case '<strike>':
 | 
						|
				case '<strike/>': font.strike = 1; break;
 | 
						|
				case '</strike>': break;
 | 
						|
 | 
						|
				/* 18.4.13 u CT_UnderlineProperty */
 | 
						|
				case '<u':
 | 
						|
					if(!y.val) break;
 | 
						|
					switch(y.val) {
 | 
						|
						case 'double': font.uval = "double"; break;
 | 
						|
						case 'singleAccounting': font.uval = "single-accounting"; break;
 | 
						|
						case 'doubleAccounting': font.uval = "double-accounting"; break;
 | 
						|
					}
 | 
						|
					/* falls through */
 | 
						|
				case '<u>':
 | 
						|
				case '<u/>': font.u = 1; break;
 | 
						|
				case '</u>': break;
 | 
						|
 | 
						|
				/* 18.8.2 b */
 | 
						|
				case '<b':
 | 
						|
					if(y.val == '0') break;
 | 
						|
					/* falls through */
 | 
						|
				case '<b>':
 | 
						|
				case '<b/>': font.b = 1; break;
 | 
						|
				case '</b>': break;
 | 
						|
 | 
						|
				/* 18.8.26 i */
 | 
						|
				case '<i':
 | 
						|
					if(y.val == '0') break;
 | 
						|
					/* falls through */
 | 
						|
				case '<i>':
 | 
						|
				case '<i/>': font.i = 1; break;
 | 
						|
				case '</i>': break;
 | 
						|
 | 
						|
				/* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
 | 
						|
				case '<color':
 | 
						|
					if(y.rgb) font.color = y.rgb.substr(2,6);
 | 
						|
					break;
 | 
						|
 | 
						|
				/* 18.8.18 family ST_FontFamily */
 | 
						|
				case '<family': font.family = y.val; break;
 | 
						|
 | 
						|
				/* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
 | 
						|
				case '<vertAlign': align = y.val; break;
 | 
						|
 | 
						|
				/* 18.8.35 scheme CT_FontScheme TODO */
 | 
						|
				case '<scheme': break;
 | 
						|
 | 
						|
				default:
 | 
						|
					if(y[0].charCodeAt(1) !== 47) throw 'Unrecognized rich format ' + y[0];
 | 
						|
			}
 | 
						|
		}
 | 
						|
		var style = [];
 | 
						|
 | 
						|
		if(font.u) style.push("text-decoration: underline;");
 | 
						|
		if(font.uval) style.push("text-underline-style:" + font.uval + ";");
 | 
						|
		if(font.sz) style.push("font-size:" + font.sz + ";");
 | 
						|
		if(font.outline) style.push("text-effect: outline;");
 | 
						|
		if(font.shadow) style.push("text-shadow: auto;");
 | 
						|
		intro.push('<span style="' + style.join("") + '">');
 | 
						|
 | 
						|
		if(font.b) { intro.push("<b>"); outro.push("</b>"); }
 | 
						|
		if(font.i) { intro.push("<i>"); outro.push("</i>"); }
 | 
						|
		if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
 | 
						|
 | 
						|
		if(align == "superscript") align = "sup";
 | 
						|
		else if(align == "subscript") align = "sub";
 | 
						|
		if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
 | 
						|
 | 
						|
		outro.push("</span>");
 | 
						|
		return cp;
 | 
						|
	};
 | 
						|
 | 
						|
	/* 18.4.4 r CT_RElt */
 | 
						|
	function parse_r(r) {
 | 
						|
		var terms = [[],"",[]];
 | 
						|
		/* 18.4.12 t ST_Xstring */
 | 
						|
		var t = r.match(tregex), cp = 65001;
 | 
						|
		if(!isval(t)/*:: || !t*/) return "";
 | 
						|
		terms[1] = t[1];
 | 
						|
 | 
						|
		var rpr = r.match(rpregex);
 | 
						|
		if(isval(rpr)/*:: && rpr*/) cp = parse_rpr(rpr[1], terms[0], terms[2]);
 | 
						|
 | 
						|
		return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
 | 
						|
	}
 | 
						|
	return function parse_rs(rs) {
 | 
						|
		return rs.replace(rregex,"").split(rend).map(parse_r).join("");
 | 
						|
	};
 | 
						|
})();
 | 
						|
 | 
						|
/* 18.4.8 si CT_Rst */
 | 
						|
var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
 | 
						|
var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
 | 
						|
function parse_si(x, opts) {
 | 
						|
	var html = opts ? opts.cellHTML : true;
 | 
						|
	var z = {};
 | 
						|
	if(!x) return null;
 | 
						|
	var y;
 | 
						|
	/* 18.4.12 t ST_Xstring (Plaintext String) */
 | 
						|
	// TODO: is whitespace actually valid here?
 | 
						|
	if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
 | 
						|
		z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
 | 
						|
		z.r = utf8read(x);
 | 
						|
		if(html) z.h = escapehtml(z.t);
 | 
						|
	}
 | 
						|
	/* 18.4.4 r CT_RElt (Rich Text Run) */
 | 
						|
	else if((y = x.match(sirregex))) {
 | 
						|
		z.r = utf8read(x);
 | 
						|
		z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
 | 
						|
		if(html) z.h = parse_rs(z.r);
 | 
						|
	}
 | 
						|
	/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
 | 
						|
	/* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
 | 
						|
	return z;
 | 
						|
}
 | 
						|
 | 
						|
/* 18.4 Shared String Table */
 | 
						|
var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
 | 
						|
var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
 | 
						|
var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
 | 
						|
function parse_sst_xml(data/*:string*/, opts)/*:SST*/ {
 | 
						|
	var s/*:SST*/ = ([]/*:any*/), ss = "";
 | 
						|
	if(!data) return s;
 | 
						|
	/* 18.4.9 sst CT_Sst */
 | 
						|
	var sst = data.match(sstr0);
 | 
						|
	if(isval(sst)/*:: && sst*/) {
 | 
						|
		ss = sst[2].replace(sstr1,"").split(sstr2);
 | 
						|
		for(var i = 0; i != ss.length; ++i) {
 | 
						|
			var o = parse_si(ss[i].trim(), opts);
 | 
						|
			if(o != null) s[s.length] = o;
 | 
						|
		}
 | 
						|
		sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
 | 
						|
	}
 | 
						|
	return s;
 | 
						|
}
 | 
						|
 | 
						|
RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
 | 
						|
var straywsregex = /^\s|\s$|[\t\n\r]/;
 | 
						|
function write_sst_xml(sst/*:SST*/, opts)/*:string*/ {
 | 
						|
	if(!opts.bookSST) return "";
 | 
						|
	var o = [XML_HEADER];
 | 
						|
	o[o.length] = (writextag('sst', null, {
 | 
						|
		xmlns: XMLNS.main[0],
 | 
						|
		count: sst.Count,
 | 
						|
		uniqueCount: sst.Unique
 | 
						|
	}));
 | 
						|
	for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
 | 
						|
		var s/*:XLString*/ = sst[i];
 | 
						|
		var sitag = "<si>";
 | 
						|
		if(s.r) sitag += s.r;
 | 
						|
		else {
 | 
						|
			sitag += "<t";
 | 
						|
			if(!s.t) s.t = "";
 | 
						|
			if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
 | 
						|
			sitag += ">" + escapexml(s.t) + "</t>";
 | 
						|
		}
 | 
						|
		sitag += "</si>";
 | 
						|
		o[o.length] = (sitag);
 | 
						|
	}
 | 
						|
	if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
 | 
						|
	return o.join("");
 | 
						|
}
 |