diff --git a/xlsx.js b/xlsx.js
index b2e6292..0c77957 100644
--- a/xlsx.js
+++ b/xlsx.js
@@ -95,15 +95,21 @@ var strs = {}; // shared strings
 
 function parseSheet(data) { //TODO: use a real xml parser
 	var s = {};
-	s["!ref"] = data.match(/<dimension ref="([^"]*)"\s*\/>/)[1];
+	var ref = data.match(/<dimension ref="([^"]*)"\s*\/>/);
+	if(ref) s["!ref"] = ref[1];
+	var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
 	//s.rows = {};
 	//s.cells = {};
 	var q = ["v","f"];
 	if(!data.match(/<sheetData *\/>/)) 
 	data.match(/<sheetData>(.*)<\/sheetData>/)[1].split("</row>").forEach(function(x) { if(x === "") return;
 		var row = parsexmltag(x.match(/<row[^>]*>/)[0]); //s.rows[row.r]=row.spans;
+		if(refguess.s.r > row.r - 1) refguess.s.r = row.r - 1; 
+		if(refguess.e.r < row.r - 1) refguess.e.r = row.r - 1;
 		var cells = x.substr(x.indexOf('>')+1).split(/<\/c>|\/>/);
-		cells.forEach(function(c) { if(c === "") return;
+		cells.forEach(function(c, idx) { if(c === "") return;
+			if(refguess.s.c > idx) refguess.s.c = idx; 
+			if(refguess.e.c < idx) refguess.e.c = idx;
 			var cell = parsexmltag((c.match(/<c[^>]*>/)||[c])[0]); delete cell[0];
 			var d = c.substr(c.indexOf('>')+1);
 			var p = {};
@@ -121,7 +127,8 @@ function parseSheet(data) { //TODO: use a real xml parser
 			s[cell.r] = p;
 		});
 	});
-	
+	if(!s["!ref"]) s["!ref"] = encode_range(refguess);
+
 	if(debug) s.rawdata = data;
 	return s;
 }
@@ -227,6 +234,7 @@ function parseWB(data) {
 			case '<calcPr': delete y[0]; wb.CalcPr = y; break;
 			case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
 			
+			case '<definedNames/>': break;
 			case '<mx:ArchID': break;
 			case '<ext': break;//TODO: check with different versions of excel
 			default: console.log(y);
@@ -255,10 +263,18 @@ function parseZip(zip) {
 	if(dir.calcchain) deps=parseDeps(zip.files[dir.calcchain.replace(/^\//,'')].data);
 	if(dir.strs[0]) strs=parseStrs(zip.files[dir.strs[0].replace(/^\//,'')].data);
 	var sheets = {};
+	if(!props.Worksheets) {
+		var wbsheets = wb.Sheets;
+		props.Worksheets = wbsheets.length;
+		props.SheetNames = [];
+		for(var j = 0; j != wbsheets.length; ++j) {
+			props.SheetNames[j] = wbsheets[j].name;
+		}
+	}
 	for(var i = 0; i != props.Worksheets; ++i) {
 		sheets[props.SheetNames[i]]=parseSheet(zip.files[dir.sheets[i].replace(/^\//,'')].data);
 	}
-	
+
 	return {
 		Directory: dir,
 		Workbook: wb,
@@ -312,7 +328,7 @@ function decode_row(rowstr) { return Number(rowstr) - 1; }
 function split_cell(cstr) { return cstr.replace(/(\$?[A-Z]*)(\$?[0-9]*)/,"$1,$2").split(","); }
 function decode_cell(cstr) { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
 function decode_range(range) { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
-
+function encode_range(range) { return encode_cell(range.s) + ":" + encode_cell(range.e); }
 /**
  * Convert a sheet into an array of objects where the column headers are keys.
  **/
@@ -370,7 +386,7 @@ function sheet_to_csv(sheet) {
 			case 's': case 'str': return JSON.stringify(val.v);
 			default: throw 'unrecognized type ' + val.t;
 		}
-	}
+	};
 	var out = "";
 	if(sheet["!ref"]) {
 		var r = utils.decode_range(sheet["!ref"]);
@@ -390,6 +406,7 @@ var utils = {
 	encode_col: encode_col,
 	encode_row: encode_row,
 	encode_cell: encode_cell,
+	encode_range: encode_range,
 	decode_col: decode_col,
 	decode_row: decode_row,
 	split_cell: split_cell,