forked from sheetjs/sheetjs
		
	version bump 0.18.3
- XLSX / XLSB dynamic array formulae - use Uint8Array when available in write (fixes #2539 h/t @RScherzer) - mini build cleanup to satiate webpack (fixes #2526 #2530)
This commit is contained in:
		
							parent
							
								
									4f6a849a59
								
							
						
					
					
						commit
						e14aee3e51
					
				@ -41,6 +41,7 @@ ExtendScript
 | 
			
		||||
IndexedDB
 | 
			
		||||
JavaScriptCore
 | 
			
		||||
LocalStorage
 | 
			
		||||
NestJS
 | 
			
		||||
NPM
 | 
			
		||||
Nuxt.js
 | 
			
		||||
Redis
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										7
									
								
								Makefile
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								Makefile
									
									
									
									
									
								
							@ -18,6 +18,7 @@ ESMJSDEPS=$(shell cat misc/mjs.lst)
 | 
			
		||||
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
 | 
			
		||||
DEPS=$(sort $(wildcard bits/*.js))
 | 
			
		||||
TSBITS=$(patsubst modules/%,bits/%,$(wildcard modules/[0-9][0-9]_*.js))
 | 
			
		||||
MTSBITS=$(patsubst modules/%,misc/%,$(wildcard modules/[0-9][0-9]_*.js))
 | 
			
		||||
TARGET=$(LIB).js
 | 
			
		||||
FLOWTARGET=$(LIB).flow.js
 | 
			
		||||
FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS))
 | 
			
		||||
@ -52,6 +53,9 @@ bits/18_cfb.js: node_modules/cfb/xlscfb.flow.js
 | 
			
		||||
$(TSBITS): bits/%: modules/%
 | 
			
		||||
	cp $^ $@
 | 
			
		||||
 | 
			
		||||
$(MTSBITS): misc/%: modules/%
 | 
			
		||||
	cp $^ $@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
clean: ## Remove targets and build artifacts
 | 
			
		||||
@ -82,6 +86,7 @@ dist: dist-deps $(TARGET) bower.json ## Prepare JS files for distribution
 | 
			
		||||
	uglifyjs $(REQS) dist/$(TARGET) $(UGLIFYOPTS) -o dist/$(LIB).core.min.js --source-map dist/$(LIB).core.min.map --preamble "$$(head -n 1 bits/00_header.js)"
 | 
			
		||||
	misc/strip_sourcemap.sh dist/$(LIB).core.min.js
 | 
			
		||||
	@# full
 | 
			
		||||
	#cat <(head -n 1 bits/00_header.js) $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) > dist/$(LIB).full.js
 | 
			
		||||
	uglifyjs $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) $(UGLIFYOPTS) -o dist/$(LIB).full.min.js --source-map dist/$(LIB).full.min.map --preamble "$$(head -n 1 bits/00_header.js)"
 | 
			
		||||
	misc/strip_sourcemap.sh dist/$(LIB).full.min.js
 | 
			
		||||
	@# mini
 | 
			
		||||
@ -101,7 +106,7 @@ dist-deps: ## Copy dependencies for distribution
 | 
			
		||||
aux: $(AUXTARGETS)
 | 
			
		||||
 | 
			
		||||
BYTEFILEC=dist/xlsx.{full,core,mini}.min.js
 | 
			
		||||
BYTEFILER=dist/xlsx.extendscript.js
 | 
			
		||||
BYTEFILER=dist/xlsx.extendscript.js xlsx.mjs
 | 
			
		||||
.PHONY: bytes
 | 
			
		||||
bytes: ## Display minified and gzipped file sizes
 | 
			
		||||
	@for i in $(BYTEFILEC); do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										572
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										572
									
								
								README.md
									
									
									
									
									
								
							@ -24,12 +24,8 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
<details><summary><b>Diagram Legend</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
## Table of Contents
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
@ -46,14 +42,17 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
 | 
			
		||||
  * [Parsing Workbooks](#parsing-workbooks)
 | 
			
		||||
  * [Processing JSON and JS Data](#processing-json-and-js-data)
 | 
			
		||||
  * [Processing HTML Tables](#processing-html-tables)
 | 
			
		||||
- [Working with the Workbook](#working-with-the-workbook)
 | 
			
		||||
  * [Parsing and Writing Examples](#parsing-and-writing-examples)
 | 
			
		||||
- [Processing Data](#processing-data)
 | 
			
		||||
  * [Modifying Workbook Structure](#modifying-workbook-structure)
 | 
			
		||||
  * [Modifying Cell Values](#modifying-cell-values)
 | 
			
		||||
  * [Modifying Other Worksheet / Workbook / Cell Properties](#modifying-other-worksheet--workbook--cell-properties)
 | 
			
		||||
- [Packaging and Releasing Data](#packaging-and-releasing-data)
 | 
			
		||||
  * [Writing Workbooks](#writing-workbooks)
 | 
			
		||||
  * [Writing Examples](#writing-examples)
 | 
			
		||||
  * [Streaming Write](#streaming-write)
 | 
			
		||||
  * [Generating JSON and JS Data](#generating-json-and-js-data)
 | 
			
		||||
  * [Generating HTML Tables](#generating-html-tables)
 | 
			
		||||
  * [Generating Single-Worksheet Snapshots](#generating-single-worksheet-snapshots)
 | 
			
		||||
- [Interface](#interface)
 | 
			
		||||
  * [Parsing functions](#parsing-functions)
 | 
			
		||||
  * [Writing functions](#writing-functions)
 | 
			
		||||
@ -150,10 +149,11 @@ For example, `unpkg` makes the latest version available at:
 | 
			
		||||
 | 
			
		||||
The complete single-file version is generated at `dist/xlsx.full.min.js`
 | 
			
		||||
 | 
			
		||||
`dist/xlsx.core.min.js` omits codepage library (no support for XLS encodings)
 | 
			
		||||
 | 
			
		||||
A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build:
 | 
			
		||||
- codepage library skipped (no support for XLS encodings)
 | 
			
		||||
- XLSX compression option not currently available
 | 
			
		||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003
 | 
			
		||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers
 | 
			
		||||
- node stream utils removed
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
@ -317,6 +317,18 @@ and approaches for steps 1 and 5.
 | 
			
		||||
 | 
			
		||||
Utility functions help with step 3.
 | 
			
		||||
 | 
			
		||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
 | 
			
		||||
solutions for common data import scenarios.
 | 
			
		||||
 | 
			
		||||
["Packaging and Releasing Data"](#packaging-and-releasing-data) describes
 | 
			
		||||
solutions for common data export scenarios.
 | 
			
		||||
 | 
			
		||||
["Processing Data"](#packaging-and-releasing-data) describes solutions for
 | 
			
		||||
common workbook processing and manipulation scenarios.
 | 
			
		||||
 | 
			
		||||
["Utility Functions"](#utility-functions) details utility functions for
 | 
			
		||||
translating JSON Arrays and other common JS structures into worksheet objects.
 | 
			
		||||
 | 
			
		||||
### The Zen of SheetJS
 | 
			
		||||
 | 
			
		||||
_Data processing should fit in any workflow_
 | 
			
		||||
@ -325,15 +337,6 @@ The library does not impose a separate lifecycle.  It fits nicely in websites
 | 
			
		||||
and apps built using any framework.  The plain JS data objects play nice with
 | 
			
		||||
Web Workers and future APIs.
 | 
			
		||||
 | 
			
		||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
 | 
			
		||||
solutions for common data import scenarios.
 | 
			
		||||
 | 
			
		||||
["Writing Workbooks"](#writing-workbooks) describes solutions for common data
 | 
			
		||||
export scenarios involving actual spreadsheet files.
 | 
			
		||||
 | 
			
		||||
["Utility Functions"](#utility-functions) details utility functions for
 | 
			
		||||
translating JSON Arrays and other common JS structures into worksheet objects.
 | 
			
		||||
 | 
			
		||||
_JavaScript is a powerful language for data processing_
 | 
			
		||||
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
 | 
			
		||||
@ -576,6 +579,12 @@ The [`demos` directory](demos/) includes sample projects for:
 | 
			
		||||
 | 
			
		||||
Other examples are included in the [showcase](demos/showcase/).
 | 
			
		||||
 | 
			
		||||
<https://sheetjs.com/demos/modify.html> shows a complete example of reading,
 | 
			
		||||
modifying, and writing files.
 | 
			
		||||
 | 
			
		||||
<https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line
 | 
			
		||||
tool included with node installations, reading spreadsheet files and exporting
 | 
			
		||||
the contents in various formats.
 | 
			
		||||
## Acquiring and Extracting Data
 | 
			
		||||
 | 
			
		||||
### Parsing Workbooks
 | 
			
		||||
@ -1018,12 +1027,13 @@ const workbook = XLSX.read(data);
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
More detailed examples are covered in the [included demos](demos/)
 | 
			
		||||
 | 
			
		||||
### Processing JSON and JS Data
 | 
			
		||||
 | 
			
		||||
JSON and JS data tend to represent single worksheets.  This section will use a
 | 
			
		||||
few utility functions to generate workbooks:
 | 
			
		||||
few utility functions to generate workbooks.
 | 
			
		||||
 | 
			
		||||
_Create a new Worksheet_
 | 
			
		||||
_Create a new Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var workbook = XLSX.utils.book_new();
 | 
			
		||||
@ -1031,16 +1041,9 @@ var workbook = XLSX.utils.book_new();
 | 
			
		||||
 | 
			
		||||
The `book_new` utility function creates an empty workbook with no worksheets.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_Append a Worksheet to a Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
 | 
			
		||||
The third argument specifies the desired worksheet name. Multiple worksheets can
 | 
			
		||||
be added to a workbook by calling the function multiple times.
 | 
			
		||||
Spreadsheet software generally require at least one worksheet and enforce the
 | 
			
		||||
requirement in the user interface.  This library enforces the requirement at
 | 
			
		||||
write time, throwing errors if an empty workbook is passed to write functions.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**API**
 | 
			
		||||
@ -1053,14 +1056,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts);
 | 
			
		||||
 | 
			
		||||
The `aoa_to_sheet` utility function walks an "array of arrays" in row-major
 | 
			
		||||
order, generating a worksheet object.  The following snippet generates a sheet
 | 
			
		||||
with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc:
 | 
			
		||||
with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  ["A1", "B1", "C1"],
 | 
			
		||||
  ["A2", "B2", "C2"],
 | 
			
		||||
  ["A3", "B3", "C3"]
 | 
			
		||||
])
 | 
			
		||||
]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
 | 
			
		||||
@ -1361,41 +1364,57 @@ const workbook = XLSX.utils.table_to_book(doc);
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
## Working with the Workbook
 | 
			
		||||
## Processing Data
 | 
			
		||||
 | 
			
		||||
The full object format is described later in this README.
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
 | 
			
		||||
representation of the core concepts of a workbook.  The utility functions work
 | 
			
		||||
with the object representation and are intended to handle common use cases.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Reading a specific cell </b> (click to show)</summary>
 | 
			
		||||
### Modifying Workbook Structure
 | 
			
		||||
 | 
			
		||||
This example extracts the value stored in cell A1 from the first worksheet:
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Append a Worksheet to a Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var first_sheet_name = workbook.SheetNames[0];
 | 
			
		||||
var address_of_cell = 'A1';
 | 
			
		||||
 | 
			
		||||
/* Get worksheet */
 | 
			
		||||
var worksheet = workbook.Sheets[first_sheet_name];
 | 
			
		||||
 | 
			
		||||
/* Find desired cell */
 | 
			
		||||
var desired_cell = worksheet[address_of_cell];
 | 
			
		||||
 | 
			
		||||
/* Get the value */
 | 
			
		||||
var desired_value = (desired_cell ? desired_cell.v : undefined);
 | 
			
		||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
 | 
			
		||||
The third argument specifies the desired worksheet name. Multiple worksheets can
 | 
			
		||||
be added to a workbook by calling the function multiple times.
 | 
			
		||||
 | 
			
		||||
_List the Worksheet names in tab order_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var wsnames = workbook.SheetNames;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `SheetNames` property of the workbook object is a list of the worksheet
 | 
			
		||||
names in "tab order".  API functions will look at this array.
 | 
			
		||||
 | 
			
		||||
_Replace a Worksheet in place_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
workbook.Sheets[sheet_name] = new_worksheet;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `Sheets` property of the workbook object is an object whose keys are names
 | 
			
		||||
and whose values are worksheet objects.  By reassigning to a property of the
 | 
			
		||||
`Sheets` object, the worksheet object can be changed without disrupting the
 | 
			
		||||
rest of the worksheet structure.
 | 
			
		||||
 | 
			
		||||
**Examples**
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Adding a new worksheet to a workbook</b> (click to show)</summary>
 | 
			
		||||
  <summary><b>Add a new worksheet to a workbook</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a
 | 
			
		||||
sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook:
 | 
			
		||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input).
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var ws_name = "SheetJS";
 | 
			
		||||
 | 
			
		||||
/* make worksheet */
 | 
			
		||||
/* Create worksheet */
 | 
			
		||||
var ws_data = [
 | 
			
		||||
  [ "S", "h", "e", "e", "t", "J", "S" ],
 | 
			
		||||
  [  1 ,  2 ,  3 ,  4 ,  5 ]
 | 
			
		||||
@ -1408,41 +1427,60 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name);
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Creating a new workbook from scratch</b> (click to show)</summary>
 | 
			
		||||
### Modifying Cell Values
 | 
			
		||||
 | 
			
		||||
The workbook object contains a `SheetNames` array of names and a `Sheets` object
 | 
			
		||||
mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function
 | 
			
		||||
creates a new workbook object:
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Modify a single cell value in a worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/* create a new blank workbook */
 | 
			
		||||
var wb = XLSX.utils.book_new();
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The new workbook is blank and contains no worksheets. The write functions will
 | 
			
		||||
error if the workbook is empty.
 | 
			
		||||
_Modify multiple cell values in a worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, aoa, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `sheet_add_aoa` utility function modifies cell values in a worksheet.  The
 | 
			
		||||
first argument is the worksheet object.  The second argument is an array of
 | 
			
		||||
arrays of values.  The `origin` key of the third argument controls where cells
 | 
			
		||||
will be written.  The following snippet sets `B3=1` and `E5="abc"`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [
 | 
			
		||||
  [1],                             // <-- Write 1 to cell B3
 | 
			
		||||
  ,                                // <-- Do nothing in row 4
 | 
			
		||||
  [/*B5*/, /*C5*/, /*D5*/, "abc"]  // <-- Write "abc" to cell E5
 | 
			
		||||
], { origin: "B3" });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
 | 
			
		||||
optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
**Examples**
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Appending rows to a worksheet</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
The special origin value `-1` instructs `sheet_add_aoa` to start in column A of
 | 
			
		||||
the row after the last row in the range, appending the data:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [
 | 
			
		||||
  ["first row after data", 1],
 | 
			
		||||
  ["second row after data", 2]
 | 
			
		||||
], { origin: -1 });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Parsing and Writing Examples
 | 
			
		||||
### Modifying Other Worksheet / Workbook / Cell Properties
 | 
			
		||||
 | 
			
		||||
- <https://sheetjs.com/demos/modify.html> read + modify + write files
 | 
			
		||||
 | 
			
		||||
- <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node
 | 
			
		||||
 | 
			
		||||
The node version installs a command line tool `xlsx` which can read spreadsheet
 | 
			
		||||
files and output the contents in various formats.  The source is available at
 | 
			
		||||
`xlsx.njs` in the bin directory.
 | 
			
		||||
 | 
			
		||||
Some helper functions in `XLSX.utils` generate different views of the sheets:
 | 
			
		||||
 | 
			
		||||
- `XLSX.utils.sheet_to_csv` generates CSV
 | 
			
		||||
- `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text
 | 
			
		||||
- `XLSX.utils.sheet_to_html` generates HTML
 | 
			
		||||
- `XLSX.utils.sheet_to_json` generates an array of objects
 | 
			
		||||
- `XLSX.utils.sheet_to_formulae` generates a list of formulae
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes
 | 
			
		||||
the object structures in greater detail.
 | 
			
		||||
 | 
			
		||||
## Packaging and Releasing Data
 | 
			
		||||
 | 
			
		||||
@ -1963,6 +2001,45 @@ The [`vuejs` demo](demos/vue) includes more React examples.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### Generating Single-Worksheet Snapshots
 | 
			
		||||
 | 
			
		||||
The `sheet_to_*` functions accept a worksheet object.
 | 
			
		||||
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Generate a CSV from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var csv = XLSX.utils.sheet_to_csv(worksheet, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type.
 | 
			
		||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
 | 
			
		||||
function and the optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
_Generate "Text" from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var txt = XLSX.utils.sheet_to_txt(worksheet, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type.
 | 
			
		||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
 | 
			
		||||
function and the optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
_Generate a list of formulae from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var fmla = XLSX.utils.sheet_to_formulae(worksheet);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot generates an array of entries representing the embedded formulae.
 | 
			
		||||
Array formulae are rendered in the form `range=formula` while plain cells are
 | 
			
		||||
rendered in the form `cell=formula or value`.  String literals are prefixed with
 | 
			
		||||
an apostrophe `'`, consistent with Excel's formula bar display.
 | 
			
		||||
 | 
			
		||||
["Formulae Output"](#formulae-output) describes the function in more detail.
 | 
			
		||||
 | 
			
		||||
## Interface
 | 
			
		||||
 | 
			
		||||
`XLSX` is the exposed variable in the browser and the exported node variable
 | 
			
		||||
@ -2065,6 +2142,7 @@ Cell objects are plain JS objects with keys and values following the convention:
 | 
			
		||||
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
 | 
			
		||||
| `f` | cell formula encoded as an A1-style string (if applicable)             |
 | 
			
		||||
| `F` | range of enclosing array if formula is array formula (if applicable)   |
 | 
			
		||||
| `D` | if true, array formula is dynamic (if applicable)                      |
 | 
			
		||||
| `r` | rich text encoding (if applicable)                                     |
 | 
			
		||||
| `h` | HTML rendering of the rich text (if applicable)                        |
 | 
			
		||||
| `c` | comments associated with the cell                                      |
 | 
			
		||||
@ -2416,79 +2494,7 @@ Even though some formats store formulae with a leading equal sign, CSF formulae
 | 
			
		||||
do not start with `=`.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Representation of A1=1, A2=2, A3=A1+A2</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
{
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:1 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', v:3, f:'A1+A2' }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
Shared formulae are decompressed and each cell has the formula corresponding to
 | 
			
		||||
its cell.  Writers generally do not attempt to generate shared formulae.
 | 
			
		||||
 | 
			
		||||
Cells with formula entries but no value will be serialized in a way that Excel
 | 
			
		||||
and other spreadsheet tools will recognize.  This library will not automatically
 | 
			
		||||
compute formula results!  For example, to compute `BESSELJ` in a worksheet:
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Formula without known value</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
{
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:3.14159 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', f:'BESSELJ(A1,A2)' }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
**Array Formulae**
 | 
			
		||||
 | 
			
		||||
Array formulae are stored in the top-left cell of the array block.  All cells
 | 
			
		||||
of an array formula have a `F` field corresponding to the range.  A single-cell
 | 
			
		||||
formula can be distinguished from a plain formula by the presence of `F` field.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Array Formula examples</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For a multi-cell array formula, every cell has the same array range but only the
 | 
			
		||||
first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
 | 
			
		||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
Utilities and writers are expected to check for the presence of a `F` field and
 | 
			
		||||
ignore any possible formula element `f` in cells other than the starting cell.
 | 
			
		||||
They are not expected to perform validation of the formulae!
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Formula Output Utility Function</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
The `sheet_to_formulae` method generates one line per formula or array formula.
 | 
			
		||||
Array formulae are rendered in the form `range=formula` while plain cells are
 | 
			
		||||
rendered in the form `cell=formula or value`.  Note that string literals are
 | 
			
		||||
prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Formulae File Format Details</b> (click to show)</summary>
 | 
			
		||||
  <summary><b>Formulae File Format Support</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
| Storage Representation | Formats                  | Read  | Write |
 | 
			
		||||
|:-----------------------|:-------------------------|:-----:|:-----:|
 | 
			
		||||
@ -2502,6 +2508,272 @@ Since Excel prohibits named cells from colliding with names of A1 or RC style
 | 
			
		||||
cell references, a (not-so-simple) regex conversion is possible.  BIFF Parsed
 | 
			
		||||
formulae and Lotus Parsed formulae have to be explicitly unwound.  OpenFormula
 | 
			
		||||
formulae can be converted with regular expressions.
 | 
			
		||||
 | 
			
		||||
Shared formulae are decompressed and each cell has the formula corresponding to
 | 
			
		||||
its cell.  Writers generally do not attempt to generate shared formulae.
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
**Single-Cell Formulae**
 | 
			
		||||
 | 
			
		||||
For simple formulae, the `f` key of the desired cell can be set to the actual
 | 
			
		||||
formula text.  This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = {
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:1 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', v:3, f:'A1+A2' }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Utilities like `aoa_to_sheet` will accept cell objects in lieu of values:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  [ 1 ], // A1
 | 
			
		||||
  [ 2 ], // A2
 | 
			
		||||
  [ {t: "n", v: 3, f: "A1+A2"} ] // A3
 | 
			
		||||
]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Cells with formula entries but no value will be serialized in a way that Excel
 | 
			
		||||
and other spreadsheet tools will recognize.  This library will not automatically
 | 
			
		||||
compute formula results!  For example, the following worksheet will include the
 | 
			
		||||
`BESSELJ` function but the result will not be available in JavaScript:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  [ 3.14159, 2 ], // Row "1"
 | 
			
		||||
  [ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro)
 | 
			
		||||
offers a formula calculator component for evaluating expressions, updating
 | 
			
		||||
values and dependent cells, and refreshing entire workbooks.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**Array Formulae**
 | 
			
		||||
 | 
			
		||||
_Assign an array formula_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Array formulae are stored in the top-left cell of the array block.  All cells
 | 
			
		||||
of an array formula have a `F` field corresponding to the range.  A single-cell
 | 
			
		||||
formula can be distinguished from a plain formula by the presence of `F` field.
 | 
			
		||||
 | 
			
		||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)");
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For a multi-cell array formula, every cell has the same array range but only the
 | 
			
		||||
first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3");
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
 | 
			
		||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Utilities and writers are expected to check for the presence of a `F` field and
 | 
			
		||||
ignore any possible formula element `f` in cells other than the starting cell.
 | 
			
		||||
They are not expected to perform validation of the formulae!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**Dynamic Array Formulae**
 | 
			
		||||
 | 
			
		||||
_Assign a dynamic array formula_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
 | 
			
		||||
file formats.  They are represented like normal array formulae but have special
 | 
			
		||||
cell metadata indicating that the formula should be allowed to adjust the range.
 | 
			
		||||
 | 
			
		||||
An array formula can be marked as dynamic by setting the cell's `D` property to
 | 
			
		||||
true.  The `F` range is expected but can be the set to the current cell:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Localization with Function Names**
 | 
			
		||||
 | 
			
		||||
SheetJS operates at the file level.  Excel stores formula expressions using the
 | 
			
		||||
English (United States) function names.  For non-English users, Excel uses a
 | 
			
		||||
localized set of function names.
 | 
			
		||||
 | 
			
		||||
For example, when the computer language and region is set to French (France),
 | 
			
		||||
Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function.  However,
 | 
			
		||||
in the actual file, Excel stores `SUM(A1:C3)`.
 | 
			
		||||
 | 
			
		||||
**Prefixed "Future Functions"**
 | 
			
		||||
 | 
			
		||||
Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when
 | 
			
		||||
stored in files.  When writing formula expressions using these functions, the
 | 
			
		||||
prefix is required for maximal compatibility:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// Broadest compatibility
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
 | 
			
		||||
 | 
			
		||||
// Can cause errors in spreadsheet software
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When reading a file, the `xlfn` option preserves the prefixes.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b> Functions requiring `_xlfn.` prefix</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
This list is growing with each Excel release.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
ACOT
 | 
			
		||||
ACOTH
 | 
			
		||||
AGGREGATE
 | 
			
		||||
ARABIC
 | 
			
		||||
BASE
 | 
			
		||||
BETA.DIST
 | 
			
		||||
BETA.INV
 | 
			
		||||
BINOM.DIST
 | 
			
		||||
BINOM.DIST.RANGE
 | 
			
		||||
BINOM.INV
 | 
			
		||||
BITAND
 | 
			
		||||
BITLSHIFT
 | 
			
		||||
BITOR
 | 
			
		||||
BITRSHIFT
 | 
			
		||||
BITXOR
 | 
			
		||||
BYCOL
 | 
			
		||||
BYROW
 | 
			
		||||
CEILING.MATH
 | 
			
		||||
CEILING.PRECISE
 | 
			
		||||
CHISQ.DIST
 | 
			
		||||
CHISQ.DIST.RT
 | 
			
		||||
CHISQ.INV
 | 
			
		||||
CHISQ.INV.RT
 | 
			
		||||
CHISQ.TEST
 | 
			
		||||
COMBINA
 | 
			
		||||
CONFIDENCE.NORM
 | 
			
		||||
CONFIDENCE.T
 | 
			
		||||
COT
 | 
			
		||||
COTH
 | 
			
		||||
COVARIANCE.P
 | 
			
		||||
COVARIANCE.S
 | 
			
		||||
CSC
 | 
			
		||||
CSCH
 | 
			
		||||
DAYS
 | 
			
		||||
DECIMAL
 | 
			
		||||
ERF.PRECISE
 | 
			
		||||
ERFC.PRECISE
 | 
			
		||||
EXPON.DIST
 | 
			
		||||
F.DIST
 | 
			
		||||
F.DIST.RT
 | 
			
		||||
F.INV
 | 
			
		||||
F.INV.RT
 | 
			
		||||
F.TEST
 | 
			
		||||
FIELDVALUE
 | 
			
		||||
FILTERXML
 | 
			
		||||
FLOOR.MATH
 | 
			
		||||
FLOOR.PRECISE
 | 
			
		||||
FORMULATEXT
 | 
			
		||||
GAMMA
 | 
			
		||||
GAMMA.DIST
 | 
			
		||||
GAMMA.INV
 | 
			
		||||
GAMMALN.PRECISE
 | 
			
		||||
GAUSS
 | 
			
		||||
HYPGEOM.DIST
 | 
			
		||||
IFNA
 | 
			
		||||
IMCOSH
 | 
			
		||||
IMCOT
 | 
			
		||||
IMCSC
 | 
			
		||||
IMCSCH
 | 
			
		||||
IMSEC
 | 
			
		||||
IMSECH
 | 
			
		||||
IMSINH
 | 
			
		||||
IMTAN
 | 
			
		||||
ISFORMULA
 | 
			
		||||
ISOMITTED
 | 
			
		||||
ISOWEEKNUM
 | 
			
		||||
LAMBDA
 | 
			
		||||
LET
 | 
			
		||||
LOGNORM.DIST
 | 
			
		||||
LOGNORM.INV
 | 
			
		||||
MAKEARRAY
 | 
			
		||||
MAP
 | 
			
		||||
MODE.MULT
 | 
			
		||||
MODE.SNGL
 | 
			
		||||
MUNIT
 | 
			
		||||
NEGBINOM.DIST
 | 
			
		||||
NORM.DIST
 | 
			
		||||
NORM.INV
 | 
			
		||||
NORM.S.DIST
 | 
			
		||||
NORM.S.INV
 | 
			
		||||
NUMBERVALUE
 | 
			
		||||
PDURATION
 | 
			
		||||
PERCENTILE.EXC
 | 
			
		||||
PERCENTILE.INC
 | 
			
		||||
PERCENTRANK.EXC
 | 
			
		||||
PERCENTRANK.INC
 | 
			
		||||
PERMUTATIONA
 | 
			
		||||
PHI
 | 
			
		||||
POISSON.DIST
 | 
			
		||||
QUARTILE.EXC
 | 
			
		||||
QUARTILE.INC
 | 
			
		||||
QUERYSTRING
 | 
			
		||||
RANDARRAY
 | 
			
		||||
RANK.AVG
 | 
			
		||||
RANK.EQ
 | 
			
		||||
REDUCE
 | 
			
		||||
RRI
 | 
			
		||||
SCAN
 | 
			
		||||
SEC
 | 
			
		||||
SECH
 | 
			
		||||
SEQUENCE
 | 
			
		||||
SHEET
 | 
			
		||||
SHEETS
 | 
			
		||||
SKEW.P
 | 
			
		||||
SORTBY
 | 
			
		||||
STDEV.P
 | 
			
		||||
STDEV.S
 | 
			
		||||
T.DIST
 | 
			
		||||
T.DIST.2T
 | 
			
		||||
T.DIST.RT
 | 
			
		||||
T.INV
 | 
			
		||||
T.INV.2T
 | 
			
		||||
T.TEST
 | 
			
		||||
UNICHAR
 | 
			
		||||
UNICODE
 | 
			
		||||
UNIQUE
 | 
			
		||||
VAR.P
 | 
			
		||||
VAR.S
 | 
			
		||||
WEBSERVICE
 | 
			
		||||
WEIBULL.DIST
 | 
			
		||||
XLOOKUP
 | 
			
		||||
XOR
 | 
			
		||||
Z.TEST
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
#### Row and Column Properties
 | 
			
		||||
 | 
			
		||||
@ -129,6 +129,7 @@ function wb_fmt() {
 | 
			
		||||
	seen = true;
 | 
			
		||||
	opts.cellFormula = true;
 | 
			
		||||
	opts.cellNF = true;
 | 
			
		||||
	opts.xlfn = true;
 | 
			
		||||
	if(program.output) sheetname = program.output;
 | 
			
		||||
}
 | 
			
		||||
function isfmt(m/*:string*/)/*:boolean*/ {
 | 
			
		||||
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
XLSX.version = '0.18.2';
 | 
			
		||||
XLSX.version = '0.18.3';
 | 
			
		||||
 | 
			
		||||
@ -13,7 +13,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
 | 
			
		||||
	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
 | 
			
		||||
	if(typeof Deno !== 'undefined') {
 | 
			
		||||
		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
 | 
			
		||||
		if(enc) switch(enc) {
 | 
			
		||||
		if(enc && typeof payload == "string") switch(enc) {
 | 
			
		||||
			case "utf8": payload = new TextEncoder(enc).encode(payload); break;
 | 
			
		||||
			case "binary": payload = s2ab(payload); break;
 | 
			
		||||
			/* TODO: binary equivalent */
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,6 @@
 | 
			
		||||
function parse_Int32LE(data) {
 | 
			
		||||
	return data.read_shift(4, 'i');
 | 
			
		||||
}
 | 
			
		||||
function write_UInt32LE(x/*:number*/, o) {
 | 
			
		||||
	if (!o) o = new_buf(4);
 | 
			
		||||
	o.write_shift(4, x);
 | 
			
		||||
 | 
			
		||||
@ -61,8 +61,8 @@ var ct2type/*{[string]:string}*/ = ({
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
 | 
			
		||||
 | 
			
		||||
	/* Metadata */
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "TODO",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "metadata",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
 | 
			
		||||
 | 
			
		||||
	/* PivotCache */
 | 
			
		||||
	"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
 | 
			
		||||
@ -179,6 +179,10 @@ var CT_LIST = (function(){
 | 
			
		||||
			xlsx: "application/vnd.ms-excel.macrosheet+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.macrosheet"
 | 
			
		||||
		},
 | 
			
		||||
		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.sheetMetadata"
 | 
			
		||||
		},
 | 
			
		||||
		styles: { /* Styles */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.styles"
 | 
			
		||||
@ -198,7 +202,7 @@ function new_ct()/*:any*/ {
 | 
			
		||||
		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
 | 
			
		||||
		rels:[], strs:[], comments:[], links:[],
 | 
			
		||||
		coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [], metadata: [],
 | 
			
		||||
		TODO:[], xmlns: "" }/*:any*/);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -297,6 +301,7 @@ function write_ct(ct, opts)/*:string*/ {
 | 
			
		||||
	f3('vba');
 | 
			
		||||
	f3('comments');
 | 
			
		||||
	f3('drawings');
 | 
			
		||||
	f2('metadata');
 | 
			
		||||
	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										151
									
								
								bits/51_xlmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										151
									
								
								bits/51_xlmeta.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,151 @@
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
function parse_xlmeta_xml(data, name, opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  if (!data)
 | 
			
		||||
    return out;
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  data.replace(tagregex, function(x, idx) {
 | 
			
		||||
    var y = parsexmltag(x);
 | 
			
		||||
    switch (strip_ns(y[0])) {
 | 
			
		||||
      case "<?xml":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadata":
 | 
			
		||||
      case "</metadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataTypes":
 | 
			
		||||
      case "</metadataTypes>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataType":
 | 
			
		||||
        out.Types.push({ name: y.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case "<futureMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</futureMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<rc":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</rc>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<cellMetadata":
 | 
			
		||||
      case "</cellMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<valueMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</valueMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<extLst":
 | 
			
		||||
      case "<extLst>":
 | 
			
		||||
      case "</extLst>":
 | 
			
		||||
      case "<extLst/>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<ext":
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case "</ext>":
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (!pass && opts.WTF)
 | 
			
		||||
          throw new Error("unrecognized " + y[0] + " in metadata");
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_xml() {
 | 
			
		||||
  var o = [XML_HEADER];
 | 
			
		||||
  o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>');
 | 
			
		||||
  return o.join("");
 | 
			
		||||
}
 | 
			
		||||
function parse_BrtMdtinfo(data, length) {
 | 
			
		||||
  return {
 | 
			
		||||
    flags: data.read_shift(4),
 | 
			
		||||
    version: data.read_shift(4),
 | 
			
		||||
    name: parse_XLWideString(data, length - 8)
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdtinfo(data) {
 | 
			
		||||
  var o = new_buf(12 + 2 * data.name.length);
 | 
			
		||||
  o.write_shift(4, data.flags);
 | 
			
		||||
  o.write_shift(4, data.version);
 | 
			
		||||
  write_XLWideString(data.name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdb(mdb) {
 | 
			
		||||
  var o = new_buf(4 + 8 * mdb.length);
 | 
			
		||||
  o.write_shift(4, mdb.length);
 | 
			
		||||
  for (var i = 0; i < mdb.length; ++i) {
 | 
			
		||||
    o.write_shift(4, mdb[i][0]);
 | 
			
		||||
    o.write_shift(4, mdb[i][1]);
 | 
			
		||||
  }
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsfmd(cnt, name) {
 | 
			
		||||
  var o = new_buf(8 + 2 * name.length);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  write_XLWideString(name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsmdb(cnt, cm) {
 | 
			
		||||
  var o = new_buf(8);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  o.write_shift(4, cm ? 1 : 0);
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function parse_xlmeta_bin(data, name, _opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  var opts = _opts || {};
 | 
			
		||||
  var state = [];
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  recordhopper(data, function(val, R_n, RT) {
 | 
			
		||||
    switch (RT) {
 | 
			
		||||
      case 335:
 | 
			
		||||
        out.Types.push({ name: val.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case 51:
 | 
			
		||||
        break;
 | 
			
		||||
      case 35:
 | 
			
		||||
        state.push(R_n);
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case 36:
 | 
			
		||||
        state.pop();
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if ((R_n || "").indexOf("Begin") > 0) {
 | 
			
		||||
        } else if ((R_n || "").indexOf("End") > 0) {
 | 
			
		||||
        } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
 | 
			
		||||
          throw new Error("Unexpected record " + RT + " " + R_n);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_bin() {
 | 
			
		||||
  var ba = buf_array();
 | 
			
		||||
  write_record(ba, "BrtBeginMetadata");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
 | 
			
		||||
  write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
 | 
			
		||||
    name: "XLDAPR",
 | 
			
		||||
    version: 12e4,
 | 
			
		||||
    flags: 3496657072
 | 
			
		||||
  }));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdtinfo");
 | 
			
		||||
  write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
 | 
			
		||||
  write_record(ba, "BrtBeginFmd");
 | 
			
		||||
  write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
 | 
			
		||||
  write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
 | 
			
		||||
  write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
 | 
			
		||||
  write_record(ba, "BrtFRTEnd");
 | 
			
		||||
  write_record(ba, "BrtEndFmd");
 | 
			
		||||
  write_record(ba, "BrtEndEsfmd");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
 | 
			
		||||
  write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdb");
 | 
			
		||||
  write_record(ba, "BrtEndMetadata");
 | 
			
		||||
  return ba.end();
 | 
			
		||||
}
 | 
			
		||||
@ -870,7 +870,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
 | 
			
		||||
				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
 | 
			
		||||
				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
 | 
			
		||||
				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
 | 
			
		||||
				stack.push(name);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -300,6 +300,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
 | 
			
		||||
	}
 | 
			
		||||
	if(cell.l) ws['!links'].push([ref, cell.l]);
 | 
			
		||||
	if(cell.c) ws['!comments'].push([ref, cell.c]);
 | 
			
		||||
	if(cell.D) o.cm = 1;
 | 
			
		||||
	return writextag('c', v, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -476,6 +477,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
 | 
			
		||||
			}
 | 
			
		||||
			safe_format(p, fmtid, fillid, opts, themes, styles);
 | 
			
		||||
			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
 | 
			
		||||
			if(tag.cm && opts.xlmeta) {
 | 
			
		||||
				var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
 | 
			
		||||
				if(cm && cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
			}
 | 
			
		||||
			if(dense) {
 | 
			
		||||
				var _r = decode_cell(tag.r);
 | 
			
		||||
				if(!s[_r.r]) s[_r.r] = [];
 | 
			
		||||
 | 
			
		||||
@ -538,6 +538,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
 | 
			
		||||
	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
 | 
			
		||||
 | 
			
		||||
	var cm, vm;
 | 
			
		||||
 | 
			
		||||
	recordhopper(data, function ws_parse(val, R_n, RT) {
 | 
			
		||||
		if(end) return;
 | 
			
		||||
		switch(RT) {
 | 
			
		||||
@ -595,6 +597,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
					}
 | 
			
		||||
					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;
 | 
			
		||||
@ -602,12 +605,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
				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); }
 | 
			
		||||
				}
 | 
			
		||||
				if(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x0001: /* 'BrtCellBlank' */
 | 
			
		||||
			case 0x000C: /* 'BrtShortBlank' */
 | 
			
		||||
				if(!opts.sheetStubs || pass) break;
 | 
			
		||||
				p = ({t:'z',v:undefined}/*:any*/);
 | 
			
		||||
				p = ({t:'z',v:void 0}/*:any*/);
 | 
			
		||||
				C = val[0].c == -1 ? C + 1 : val[0].c;
 | 
			
		||||
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
 | 
			
		||||
				else s[encode_col(C) + rr] = p;
 | 
			
		||||
@ -615,11 +623,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
				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(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x00B0: /* 'BrtMergeCell' */
 | 
			
		||||
				merges.push(val); break;
 | 
			
		||||
 | 
			
		||||
			case 0x0031: { /* 'BrtCellMeta' */
 | 
			
		||||
				cm = ((opts.xlmeta||{}).Types||[])[val-1];
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case 0x01EE: /* 'BrtHLink' */
 | 
			
		||||
				var rel = rels['!id'][val.relId];
 | 
			
		||||
				if(rel) {
 | 
			
		||||
@ -707,7 +724,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
			case 0x041A: /* 'BrtCFVO14' */
 | 
			
		||||
			case 0x0289: /* 'BrtCellIgnoreEC' */
 | 
			
		||||
			case 0x0451: /* 'BrtCellIgnoreEC14' */
 | 
			
		||||
			case 0x0031: /* 'BrtCellMeta' */
 | 
			
		||||
			case 0x024D: /* 'BrtCellSmartTagProperty' */
 | 
			
		||||
			case 0x025F: /* 'BrtCellWatch' */
 | 
			
		||||
			case 0x0234: /* 'BrtColor' */
 | 
			
		||||
 | 
			
		||||
@ -52,6 +52,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) {
 | 
			
		||||
	return parse_xlink_xml((data/*:any*/), rel, name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_xlmeta(data, name/*:string*/, opts) {
 | 
			
		||||
	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts);
 | 
			
		||||
	return parse_xlmeta_xml((data/*:any*/), name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_wb(wb, name/*:string*/, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
 | 
			
		||||
}
 | 
			
		||||
@ -81,3 +86,7 @@ function write_cc(data, name:string, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
function write_xlmeta(name/*:string*/) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder },
 | 
			
		||||
	/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF },
 | 
			
		||||
	/*::[*/0x0030/*::]*/: { n:"BrtStyle" },
 | 
			
		||||
	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" },
 | 
			
		||||
	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE },
 | 
			
		||||
	/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" },
 | 
			
		||||
	/*::[*/0x0033/*::]*/: { n:"BrtMdb" },
 | 
			
		||||
	/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" },
 | 
			
		||||
@ -274,7 +274,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" },
 | 
			
		||||
	/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" },
 | 
			
		||||
	/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" },
 | 
			
		||||
	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" },
 | 
			
		||||
	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
 | 
			
		||||
	/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" },
 | 
			
		||||
	/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" },
 | 
			
		||||
	/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" },
 | 
			
		||||
@ -795,7 +795,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" },
 | 
			
		||||
	/*::[*/0x0836/*::]*/: { n:"BrtDxf15" },
 | 
			
		||||
	/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" },
 | 
			
		||||
	/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" },
 | 
			
		||||
	/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" },
 | 
			
		||||
	/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" },
 | 
			
		||||
	/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" },
 | 
			
		||||
	/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" },
 | 
			
		||||
@ -835,9 +835,27 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" },
 | 
			
		||||
	/*::[*/0x0C00/*::]*/: { n:"BrtUid" },
 | 
			
		||||
	/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" },
 | 
			
		||||
	/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" },
 | 
			
		||||
	/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" },
 | 
			
		||||
	/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" },
 | 
			
		||||
	/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" },
 | 
			
		||||
	/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" },
 | 
			
		||||
	/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" },
 | 
			
		||||
	/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" },
 | 
			
		||||
	/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" },
 | 
			
		||||
	/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" },
 | 
			
		||||
	/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" },
 | 
			
		||||
	/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" },
 | 
			
		||||
	/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" },
 | 
			
		||||
	/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" },
 | 
			
		||||
	/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" },
 | 
			
		||||
	/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" },
 | 
			
		||||
	/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" },
 | 
			
		||||
	/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" },
 | 
			
		||||
	/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" },
 | 
			
		||||
	/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" },
 | 
			
		||||
	/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" },
 | 
			
		||||
	/*::[*/0xFFFF/*::]*/: { n:"" }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -161,9 +161,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
 | 
			
		||||
	var wbrelsi = dir.workbooks[0].lastIndexOf("/");
 | 
			
		||||
	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
 | 
			
		||||
	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
 | 
			
		||||
 | 
			
		||||
	if((dir.metadata || []).length >= 1) {
 | 
			
		||||
		/* TODO: MDX and other types of metadata */
 | 
			
		||||
		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Numbers iOS hack */
 | 
			
		||||
	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
 | 
			
		||||
	wsloop: for(i = 0; i != props.Worksheets; ++i) {
 | 
			
		||||
 | 
			
		||||
@ -124,6 +124,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta(f));
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -132,7 +137,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
	return zip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* this version does not reference XLSB write functions */
 | 
			
		||||
function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
	_shapeid = 1024;
 | 
			
		||||
	if(wb && !wb.SSF) {
 | 
			
		||||
@ -254,6 +259,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta_xml());
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
 | 
			
		||||
@ -45,14 +45,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
 | 
			
		||||
}
 | 
			
		||||
function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ {
 | 
			
		||||
	var oopts = {};
 | 
			
		||||
	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
 | 
			
		||||
	if(o.compression) oopts.compression = 'DEFLATE';
 | 
			
		||||
	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
 | 
			
		||||
	if(o.password) oopts.type = ftype;
 | 
			
		||||
	else switch(o.type) {
 | 
			
		||||
		case "base64": oopts.type = "base64"; break;
 | 
			
		||||
		case "binary": oopts.type = "string"; break;
 | 
			
		||||
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
 | 
			
		||||
		case "buffer":
 | 
			
		||||
		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
 | 
			
		||||
		case "file": oopts.type = ftype; break;
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
 | 
			
		||||
 | 
			
		||||
@ -98,7 +98,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* set array formula and flush related cells */
 | 
			
		||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) {
 | 
			
		||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) {
 | 
			
		||||
	var rng = typeof range != "string" ? range : safe_decode_range(range);
 | 
			
		||||
	var rngstr = typeof range == "string" ? range : encode_range(range);
 | 
			
		||||
	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
 | 
			
		||||
@ -106,7 +106,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri
 | 
			
		||||
		cell.t = 'n';
 | 
			
		||||
		cell.F = rngstr;
 | 
			
		||||
		delete cell.v;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) cell.f = formula;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) {
 | 
			
		||||
			cell.f = formula;
 | 
			
		||||
			if(dynamic) cell.D = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ws;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -169,8 +169,8 @@ curl -X GET http://localhost:7262/?f=sheetjs.xlsb
 | 
			
		||||
 | 
			
		||||
[NestJS](https://nestjs.com/) is a Node.js framework for server-side web applications.
 | 
			
		||||
 | 
			
		||||
This demo uses SheetJS to injest a spreadsheet via a POST API endpoint. The file
 | 
			
		||||
arrive to the endpoint as body `form-data`, accessible using the `file` key.
 | 
			
		||||
This demo uses SheetJS to parse a spreadsheet via a POST API endpoint. The file
 | 
			
		||||
arrives to the endpoint as body `form-data`, accessible using the `file` key.
 | 
			
		||||
After parsing the file, CSV contents of the first worksheet will be returned.
 | 
			
		||||
[Body parsing uses `multer`](https://docs.nestjs.com/techniques/file-upload).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								dist/xlsx.core.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										30
									
								
								dist/xlsx.core.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.core.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.core.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										322
									
								
								dist/xlsx.extendscript.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										322
									
								
								dist/xlsx.extendscript.js
									
									
									
										generated
									
									
										vendored
									
									
								
							@ -160,7 +160,7 @@ var DO_NOT_EXPORT_CODEPAGE = true;
 | 
			
		||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
 | 
			
		||||
var XLSX = {};
 | 
			
		||||
function make_xlsx_lib(XLSX){
 | 
			
		||||
XLSX.version = '0.18.2';
 | 
			
		||||
XLSX.version = '0.18.3';
 | 
			
		||||
var current_codepage = 1200, current_ansi = 1252;
 | 
			
		||||
/*global cptable:true, window */
 | 
			
		||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
 | 
			
		||||
@ -288,7 +288,7 @@ var Base64 = function() {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}();
 | 
			
		||||
var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node);
 | 
			
		||||
var has_buf = (typeof Buffer !== 'undefined' && typeof undefined !== 'undefined' && typeof ({}) !== 'undefined' && !!({}).node);
 | 
			
		||||
 | 
			
		||||
var Buffer_from = function(){};
 | 
			
		||||
 | 
			
		||||
@ -1640,7 +1640,7 @@ function parse_extra_field(blob) {
 | 
			
		||||
	return o;
 | 
			
		||||
}
 | 
			
		||||
var fs;
 | 
			
		||||
function get_fs() { return fs || (fs = require('fs')); }
 | 
			
		||||
function get_fs() { return fs || (fs = undefined); }
 | 
			
		||||
function parse(file, options) {
 | 
			
		||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
 | 
			
		||||
if((file[0] | 0x20) == 0x6d && (file[1]|0x20) == 0x69) return parse_mad(file, options);
 | 
			
		||||
@ -3256,7 +3256,7 @@ return exports;
 | 
			
		||||
 | 
			
		||||
if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
 | 
			
		||||
var _fs;
 | 
			
		||||
if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
 | 
			
		||||
if(typeof require !== 'undefined') try { _fs = undefined; } catch(e) {}
 | 
			
		||||
 | 
			
		||||
/* normalize data for blob ctor */
 | 
			
		||||
function blobify(data) {
 | 
			
		||||
@ -3270,7 +3270,7 @@ function write_dl(fname, payload, enc) {
 | 
			
		||||
	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
 | 
			
		||||
	if(typeof Deno !== 'undefined') {
 | 
			
		||||
		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
 | 
			
		||||
		if(enc) switch(enc) {
 | 
			
		||||
		if(enc && typeof payload == "string") switch(enc) {
 | 
			
		||||
			case "utf8": payload = new TextEncoder(enc).encode(payload); break;
 | 
			
		||||
			case "binary": payload = s2ab(payload); break;
 | 
			
		||||
			/* TODO: binary equivalent */
 | 
			
		||||
@ -4213,43 +4213,6 @@ function encode_range_xls(r, opts) {
 | 
			
		||||
	}
 | 
			
		||||
	return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
 | 
			
		||||
}
 | 
			
		||||
var OFFCRYPTO = {};
 | 
			
		||||
 | 
			
		||||
var make_offcrypto = function(O, _crypto) {
 | 
			
		||||
	var crypto;
 | 
			
		||||
	if(typeof _crypto !== 'undefined') crypto = _crypto;
 | 
			
		||||
	else if(typeof require !== 'undefined') {
 | 
			
		||||
		try { crypto = undefined; }
 | 
			
		||||
		catch(e) { crypto = null; }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	O.rc4 = function(key, data) {
 | 
			
		||||
		var S = new Array(256);
 | 
			
		||||
		var c = 0, i = 0, j = 0, t = 0;
 | 
			
		||||
		for(i = 0; i != 256; ++i) S[i] = i;
 | 
			
		||||
		for(i = 0; i != 256; ++i) {
 | 
			
		||||
			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
 | 
			
		||||
			t = S[i]; S[i] = S[j]; S[j] = t;
 | 
			
		||||
		}
 | 
			
		||||
		// $FlowIgnore
 | 
			
		||||
		i = j = 0; var out = new_raw_buf(data.length);
 | 
			
		||||
		for(c = 0; c != data.length; ++c) {
 | 
			
		||||
			i = (i + 1)&255;
 | 
			
		||||
			j = (j + S[i])%256;
 | 
			
		||||
			t = S[i]; S[i] = S[j]; S[j] = t;
 | 
			
		||||
			out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
 | 
			
		||||
		}
 | 
			
		||||
		return out;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	O.md5 = function(hex) {
 | 
			
		||||
		if(!crypto) throw new Error("Unsupported crypto");
 | 
			
		||||
		return crypto.createHash('md5').update(hex).digest('hex');
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
/*global crypto:true */
 | 
			
		||||
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
 | 
			
		||||
 | 
			
		||||
function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
 | 
			
		||||
function encode_row(row) { return "" + (row + 1); }
 | 
			
		||||
function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
 | 
			
		||||
@ -4414,6 +4377,9 @@ function sheet_add_aoa(_ws, data, opts) {
 | 
			
		||||
}
 | 
			
		||||
function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
 | 
			
		||||
 | 
			
		||||
function parse_Int32LE(data) {
 | 
			
		||||
	return data.read_shift(4, 'i');
 | 
			
		||||
}
 | 
			
		||||
function write_UInt32LE(x, o) {
 | 
			
		||||
	if (!o) o = new_buf(4);
 | 
			
		||||
	o.write_shift(4, x);
 | 
			
		||||
@ -5079,8 +5045,8 @@ var ct2type/*{[string]:string}*/ = ({
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
 | 
			
		||||
 | 
			
		||||
	/* Metadata */
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "TODO",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "metadata",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
 | 
			
		||||
 | 
			
		||||
	/* PivotCache */
 | 
			
		||||
	"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
 | 
			
		||||
@ -5197,6 +5163,10 @@ var CT_LIST = (function(){
 | 
			
		||||
			xlsx: "application/vnd.ms-excel.macrosheet+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.macrosheet"
 | 
			
		||||
		},
 | 
			
		||||
		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.sheetMetadata"
 | 
			
		||||
		},
 | 
			
		||||
		styles: { /* Styles */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.styles"
 | 
			
		||||
@ -5216,7 +5186,7 @@ function new_ct() {
 | 
			
		||||
		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
 | 
			
		||||
		rels:[], strs:[], comments:[], links:[],
 | 
			
		||||
		coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [], metadata: [],
 | 
			
		||||
		TODO:[], xmlns: "" });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5315,6 +5285,7 @@ function write_ct(ct, opts) {
 | 
			
		||||
	f3('vba');
 | 
			
		||||
	f3('comments');
 | 
			
		||||
	f3('drawings');
 | 
			
		||||
	f2('metadata');
 | 
			
		||||
	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
@ -5381,7 +5352,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
 | 
			
		||||
function add_rels(rels, rId, f, type, relobj, targetmode) {
 | 
			
		||||
	if(!relobj) relobj = {};
 | 
			
		||||
	if(!rels['!id']) rels['!id'] = {};
 | 
			
		||||
	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
 | 
			
		||||
	if(!rels['!idx']) rels['!idx'] = 1;
 | 
			
		||||
	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */}
 | 
			
		||||
	rels['!idx'] = rId + 1;
 | 
			
		||||
	relobj.Id = 'rId' + rId;
 | 
			
		||||
	relobj.Type = type;
 | 
			
		||||
	relobj.Target = f;
 | 
			
		||||
@ -11365,6 +11338,157 @@ function update_xfext(xf, xfext) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
function parse_xlmeta_xml(data, name, opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  if (!data)
 | 
			
		||||
    return out;
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  data.replace(tagregex, function(x, idx) {
 | 
			
		||||
    var y = parsexmltag(x);
 | 
			
		||||
    switch (strip_ns(y[0])) {
 | 
			
		||||
      case "<?xml":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadata":
 | 
			
		||||
      case "</metadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataTypes":
 | 
			
		||||
      case "</metadataTypes>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataType":
 | 
			
		||||
        out.Types.push({ name: y.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case "<futureMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</futureMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<rc":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</rc>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<cellMetadata":
 | 
			
		||||
      case "</cellMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<valueMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</valueMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<extLst":
 | 
			
		||||
      case "<extLst>":
 | 
			
		||||
      case "</extLst>":
 | 
			
		||||
      case "<extLst/>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<ext":
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case "</ext>":
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (!pass && opts.WTF)
 | 
			
		||||
          throw new Error("unrecognized " + y[0] + " in metadata");
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_xml() {
 | 
			
		||||
  var o = [XML_HEADER];
 | 
			
		||||
  o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>');
 | 
			
		||||
  return o.join("");
 | 
			
		||||
}
 | 
			
		||||
function parse_BrtMdtinfo(data, length) {
 | 
			
		||||
  return {
 | 
			
		||||
    flags: data.read_shift(4),
 | 
			
		||||
    version: data.read_shift(4),
 | 
			
		||||
    name: parse_XLWideString(data, length - 8)
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdtinfo(data) {
 | 
			
		||||
  var o = new_buf(12 + 2 * data.name.length);
 | 
			
		||||
  o.write_shift(4, data.flags);
 | 
			
		||||
  o.write_shift(4, data.version);
 | 
			
		||||
  write_XLWideString(data.name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdb(mdb) {
 | 
			
		||||
  var o = new_buf(4 + 8 * mdb.length);
 | 
			
		||||
  o.write_shift(4, mdb.length);
 | 
			
		||||
  for (var i = 0; i < mdb.length; ++i) {
 | 
			
		||||
    o.write_shift(4, mdb[i][0]);
 | 
			
		||||
    o.write_shift(4, mdb[i][1]);
 | 
			
		||||
  }
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsfmd(cnt, name) {
 | 
			
		||||
  var o = new_buf(8 + 2 * name.length);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  write_XLWideString(name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsmdb(cnt, cm) {
 | 
			
		||||
  var o = new_buf(8);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  o.write_shift(4, cm ? 1 : 0);
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function parse_xlmeta_bin(data, name, _opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  var opts = _opts || {};
 | 
			
		||||
  var state = [];
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  recordhopper(data, function(val, R_n, RT) {
 | 
			
		||||
    switch (RT) {
 | 
			
		||||
      case 335:
 | 
			
		||||
        out.Types.push({ name: val.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case 51:
 | 
			
		||||
        break;
 | 
			
		||||
      case 35:
 | 
			
		||||
        state.push(R_n);
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case 36:
 | 
			
		||||
        state.pop();
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if ((R_n || "").indexOf("Begin") > 0) {
 | 
			
		||||
        } else if ((R_n || "").indexOf("End") > 0) {
 | 
			
		||||
        } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
 | 
			
		||||
          throw new Error("Unexpected record " + RT + " " + R_n);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_bin() {
 | 
			
		||||
  var ba = buf_array();
 | 
			
		||||
  write_record(ba, "BrtBeginMetadata");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
 | 
			
		||||
  write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
 | 
			
		||||
    name: "XLDAPR",
 | 
			
		||||
    version: 12e4,
 | 
			
		||||
    flags: 3496657072
 | 
			
		||||
  }));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdtinfo");
 | 
			
		||||
  write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
 | 
			
		||||
  write_record(ba, "BrtBeginFmd");
 | 
			
		||||
  write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
 | 
			
		||||
  write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
 | 
			
		||||
  write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
 | 
			
		||||
  write_record(ba, "BrtFRTEnd");
 | 
			
		||||
  write_record(ba, "BrtEndFmd");
 | 
			
		||||
  write_record(ba, "BrtEndEsfmd");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
 | 
			
		||||
  write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdb");
 | 
			
		||||
  write_record(ba, "BrtEndMetadata");
 | 
			
		||||
  return ba.end();
 | 
			
		||||
}
 | 
			
		||||
/* 18.6 Calculation Chain */
 | 
			
		||||
function parse_cc_xml(data) {
 | 
			
		||||
	var d = [];
 | 
			
		||||
@ -12690,7 +12814,7 @@ ixti = f[1][1]; r = f[1][2];
 | 
			
		||||
				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
 | 
			
		||||
				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
 | 
			
		||||
				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
 | 
			
		||||
				stack.push(name);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
@ -14588,6 +14712,7 @@ function write_ws_xml_cell(cell, ref, ws, opts) {
 | 
			
		||||
	}
 | 
			
		||||
	if(cell.l) ws['!links'].push([ref, cell.l]);
 | 
			
		||||
	if(cell.c) ws['!comments'].push([ref, cell.c]);
 | 
			
		||||
	if(cell.D) o.cm = 1;
 | 
			
		||||
	return writextag('c', v, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14764,6 +14889,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
 | 
			
		||||
			}
 | 
			
		||||
			safe_format(p, fmtid, fillid, opts, themes, styles);
 | 
			
		||||
			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
 | 
			
		||||
			if(tag.cm && opts.xlmeta) {
 | 
			
		||||
				var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
 | 
			
		||||
				if(cm && cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
			}
 | 
			
		||||
			if(dense) {
 | 
			
		||||
				var _r = decode_cell(tag.r);
 | 
			
		||||
				if(!s[_r.r]) s[_r.r] = [];
 | 
			
		||||
@ -14846,7 +14975,7 @@ function write_ws_xml(idx, opts, wb, rels) {
 | 
			
		||||
 | 
			
		||||
	o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
 | 
			
		||||
 | 
			
		||||
	/* TODO: store in WB, process styles */
 | 
			
		||||
	/* TODO: store in WB, undefined styles */
 | 
			
		||||
	if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
 | 
			
		||||
		defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
 | 
			
		||||
		baseColWidth:opts.sheetFormat.baseColWidth||'10',
 | 
			
		||||
@ -15477,6 +15606,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
 | 
			
		||||
	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
 | 
			
		||||
 | 
			
		||||
	var cm, vm;
 | 
			
		||||
 | 
			
		||||
	recordhopper(data, function ws_parse(val, R_n, RT) {
 | 
			
		||||
		if(end) return;
 | 
			
		||||
		switch(RT) {
 | 
			
		||||
@ -15534,6 +15665,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
					}
 | 
			
		||||
					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;
 | 
			
		||||
@ -15541,12 +15673,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
				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); }
 | 
			
		||||
				}
 | 
			
		||||
				if(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x0001: /* 'BrtCellBlank' */
 | 
			
		||||
			case 0x000C: /* 'BrtShortBlank' */
 | 
			
		||||
				if(!opts.sheetStubs || pass) break;
 | 
			
		||||
				p = ({t:'z',v:undefined});
 | 
			
		||||
				p = ({t:'z',v:void 0});
 | 
			
		||||
				C = val[0].c == -1 ? C + 1 : val[0].c;
 | 
			
		||||
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
 | 
			
		||||
				else s[encode_col(C) + rr] = p;
 | 
			
		||||
@ -15554,11 +15691,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
				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(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x00B0: /* 'BrtMergeCell' */
 | 
			
		||||
				merges.push(val); break;
 | 
			
		||||
 | 
			
		||||
			case 0x0031: { /* 'BrtCellMeta' */
 | 
			
		||||
				cm = ((opts.xlmeta||{}).Types||[])[val-1];
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case 0x01EE: /* 'BrtHLink' */
 | 
			
		||||
				var rel = rels['!id'][val.relId];
 | 
			
		||||
				if(rel) {
 | 
			
		||||
@ -15646,7 +15792,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
			case 0x041A: /* 'BrtCFVO14' */
 | 
			
		||||
			case 0x0289: /* 'BrtCellIgnoreEC' */
 | 
			
		||||
			case 0x0451: /* 'BrtCellIgnoreEC14' */
 | 
			
		||||
			case 0x0031: /* 'BrtCellMeta' */
 | 
			
		||||
			case 0x024D: /* 'BrtCellSmartTagProperty' */
 | 
			
		||||
			case 0x025F: /* 'BrtCellWatch' */
 | 
			
		||||
			case 0x0234: /* 'BrtColor' */
 | 
			
		||||
@ -16851,6 +16996,11 @@ function parse_xlink(data, rel, name, opts) {
 | 
			
		||||
	return parse_xlink_xml((data), rel, name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_xlmeta(data, name, opts) {
 | 
			
		||||
	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data), name, opts);
 | 
			
		||||
	return parse_xlmeta_xml((data), name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_wb(wb, name, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
 | 
			
		||||
}
 | 
			
		||||
@ -16880,6 +17030,10 @@ function write_cc(data, name:string, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
function write_xlmeta(name) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
 | 
			
		||||
}
 | 
			
		||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
 | 
			
		||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
 | 
			
		||||
function xlml_parsexmltag(tag, skip_root) {
 | 
			
		||||
@ -18294,7 +18448,7 @@ function parse_workbook(blob, options) {
 | 
			
		||||
	var last_Rn = '';
 | 
			
		||||
	var file_depth = 0; /* TODO: make a real stack */
 | 
			
		||||
	var BIFF2Fmt = 0, BIFF2FmtTable = [];
 | 
			
		||||
	var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */
 | 
			
		||||
	var FilterDatabases = []; /* TODO: sort out supbooks and undefined elsewhere */
 | 
			
		||||
	var last_lbl;
 | 
			
		||||
 | 
			
		||||
	/* explicit override for some broken writers */
 | 
			
		||||
@ -19136,7 +19290,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
0x002E: { n:"BrtBorder", f:parse_BrtBorder },
 | 
			
		||||
0x002F: { n:"BrtXF", f:parse_BrtXF },
 | 
			
		||||
0x0030: { n:"BrtStyle" },
 | 
			
		||||
0x0031: { n:"BrtCellMeta" },
 | 
			
		||||
0x0031: { n:"BrtCellMeta", f:parse_Int32LE },
 | 
			
		||||
0x0032: { n:"BrtValueMeta" },
 | 
			
		||||
0x0033: { n:"BrtMdb" },
 | 
			
		||||
0x0034: { n:"BrtBeginFmd" },
 | 
			
		||||
@ -19362,7 +19516,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
0x014C: { n:"BrtBeginMetadata" },
 | 
			
		||||
0x014D: { n:"BrtEndMetadata" },
 | 
			
		||||
0x014E: { n:"BrtBeginEsmdtinfo" },
 | 
			
		||||
0x014F: { n:"BrtMdtinfo" },
 | 
			
		||||
0x014F: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
 | 
			
		||||
0x0150: { n:"BrtEndEsmdtinfo" },
 | 
			
		||||
0x0151: { n:"BrtBeginEsmdb" },
 | 
			
		||||
0x0152: { n:"BrtEndEsmdb" },
 | 
			
		||||
@ -19883,7 +20037,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
0x0835: { n:"BrtEndTimelineStyleElements" },
 | 
			
		||||
0x0836: { n:"BrtDxf15" },
 | 
			
		||||
0x0837: { n:"BrtBeginDxfs15" },
 | 
			
		||||
0x0838: { n:"brtEndDxfs15" },
 | 
			
		||||
0x0838: { n:"BrtEndDxfs15" },
 | 
			
		||||
0x0839: { n:"BrtSlicerCacheHideItemsWithNoData" },
 | 
			
		||||
0x083A: { n:"BrtBeginItemUniqueNames" },
 | 
			
		||||
0x083B: { n:"BrtEndItemUniqueNames" },
 | 
			
		||||
@ -19923,9 +20077,27 @@ var XLSBRecordEnum = {
 | 
			
		||||
0x085D: { n:"BrtModelTimeGroupingCalcCol" },
 | 
			
		||||
0x0C00: { n:"BrtUid" },
 | 
			
		||||
0x0C01: { n:"BrtRevisionPtr" },
 | 
			
		||||
0x13e7: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
0x13e8: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
0x13e9: { n:"BrtCalcFeature" },
 | 
			
		||||
0x1000: { n:"BrtBeginDynamicArrayPr" },
 | 
			
		||||
0x1001: { n:"BrtEndDynamicArrayPr" },
 | 
			
		||||
0x138A: { n:"BrtBeginRichValueBlock" },
 | 
			
		||||
0x138B: { n:"BrtEndRichValueBlock" },
 | 
			
		||||
0x13D9: { n:"BrtBeginRichFilters" },
 | 
			
		||||
0x13DA: { n:"BrtEndRichFilters" },
 | 
			
		||||
0x13DB: { n:"BrtRichFilter" },
 | 
			
		||||
0x13DC: { n:"BrtBeginRichFilterColumn" },
 | 
			
		||||
0x13DD: { n:"BrtEndRichFilterColumn" },
 | 
			
		||||
0x13DE: { n:"BrtBeginCustomRichFilters" },
 | 
			
		||||
0x13DF: { n:"BrtEndCustomRichFilters" },
 | 
			
		||||
0x13E0: { n:"BrtCustomRichFilter" },
 | 
			
		||||
0x13E1: { n:"BrtTop10RichFilter" },
 | 
			
		||||
0x13E2: { n:"BrtDynamicRichFilter" },
 | 
			
		||||
0x13E4: { n:"BrtBeginRichSortCondition" },
 | 
			
		||||
0x13E5: { n:"BrtEndRichSortCondition" },
 | 
			
		||||
0x13E6: { n:"BrtRichFilterDateGroupItem" },
 | 
			
		||||
0x13E7: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
0x13E8: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
0x13E9: { n:"BrtCalcFeature" },
 | 
			
		||||
0x13EB: { n:"BrtExternalLinksPr" },
 | 
			
		||||
0xFFFF: { n:"" }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -20992,7 +21164,7 @@ function sheet_add_dom(ws, table, _opts) {
 | 
			
		||||
			}
 | 
			
		||||
			if(o.z === undefined && z != null) o.z = z;
 | 
			
		||||
			/* The first link is used.  Links are assumed to be fully specified.
 | 
			
		||||
			 * TODO: The right way to process relative links is to make a new <a> */
 | 
			
		||||
			 * TODO: The right way to undefined relative links is to make a new <a> */
 | 
			
		||||
			var l = "", Aelts = elt.getElementsByTagName("A");
 | 
			
		||||
			if(Aelts && Aelts.length) for(var Aelti = 0; Aelti < Aelts.length; ++Aelti)	if(Aelts[Aelti].hasAttribute("href")) {
 | 
			
		||||
				l = Aelts[Aelti].getAttribute("href"); if(l.charAt(0) != "#") break;
 | 
			
		||||
@ -22778,9 +22950,16 @@ function parse_zip(zip, opts) {
 | 
			
		||||
	var wbrelsi = dir.workbooks[0].lastIndexOf("/");
 | 
			
		||||
	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
 | 
			
		||||
	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
 | 
			
		||||
 | 
			
		||||
	if((dir.metadata || []).length >= 1) {
 | 
			
		||||
		/* TODO: MDX and other types of metadata */
 | 
			
		||||
		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Numbers iOS hack */
 | 
			
		||||
	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
 | 
			
		||||
	wsloop: for(i = 0; i != props.Worksheets; ++i) {
 | 
			
		||||
@ -23013,6 +23192,11 @@ f = "docProps/app.xml";
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta(f));
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -23021,7 +23205,7 @@ f = "docProps/app.xml";
 | 
			
		||||
	return zip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* this version does not reference XLSB write functions */
 | 
			
		||||
function write_zip_xlsx(wb, opts) {
 | 
			
		||||
	_shapeid = 1024;
 | 
			
		||||
	if(wb && !wb.SSF) {
 | 
			
		||||
@ -23142,6 +23326,11 @@ f = "docProps/app.xml";
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta_xml());
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -23195,6 +23384,7 @@ function read_plaintext_raw(data, o) {
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
 | 
			
		||||
	o.type = "binary";
 | 
			
		||||
	return read_plaintext(str, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23313,14 +23503,15 @@ function write_zip_typeXLSX(wb, opts) {
 | 
			
		||||
}
 | 
			
		||||
function write_zip_denouement(z, o) {
 | 
			
		||||
	var oopts = {};
 | 
			
		||||
	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
 | 
			
		||||
	if(o.compression) oopts.compression = 'DEFLATE';
 | 
			
		||||
	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
 | 
			
		||||
	if(o.password) oopts.type = ftype;
 | 
			
		||||
	else switch(o.type) {
 | 
			
		||||
		case "base64": oopts.type = "base64"; break;
 | 
			
		||||
		case "binary": oopts.type = "string"; break;
 | 
			
		||||
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
 | 
			
		||||
		case "buffer":
 | 
			
		||||
		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
 | 
			
		||||
		case "file": oopts.type = ftype; break;
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
 | 
			
		||||
@ -23838,7 +24029,7 @@ utils.cell_add_comment = function(cell, text, author) {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* set array formula and flush related cells */
 | 
			
		||||
utils.sheet_set_array_formula = function(ws, range, formula) {
 | 
			
		||||
utils.sheet_set_array_formula = function(ws, range, formula, dynamic) {
 | 
			
		||||
	var rng = typeof range != "string" ? range : safe_decode_range(range);
 | 
			
		||||
	var rngstr = typeof range == "string" ? range : encode_range(range);
 | 
			
		||||
	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
 | 
			
		||||
@ -23846,7 +24037,10 @@ utils.sheet_set_array_formula = function(ws, range, formula) {
 | 
			
		||||
		cell.t = 'n';
 | 
			
		||||
		cell.F = rngstr;
 | 
			
		||||
		delete cell.v;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) cell.f = formula;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) {
 | 
			
		||||
			cell.f = formula;
 | 
			
		||||
			if(dynamic) cell.D = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ws;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								dist/xlsx.full.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										30
									
								
								dist/xlsx.full.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.full.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.full.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										16
									
								
								dist/xlsx.mini.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								dist/xlsx.mini.min.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.mini.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.mini.min.map
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -24,9 +24,5 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
<details><summary><b>Diagram Legend</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -38,7 +38,6 @@ The complete single-file version is generated at `dist/xlsx.full.min.js`
 | 
			
		||||
 | 
			
		||||
A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build:
 | 
			
		||||
- codepage library skipped (no support for XLS encodings)
 | 
			
		||||
- XLSX compression option not currently available
 | 
			
		||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers
 | 
			
		||||
- node stream utils removed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -48,6 +48,18 @@ and approaches for steps 1 and 5.
 | 
			
		||||
 | 
			
		||||
Utility functions help with step 3.
 | 
			
		||||
 | 
			
		||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
 | 
			
		||||
solutions for common data import scenarios.
 | 
			
		||||
 | 
			
		||||
["Packaging and Releasing Data"](#packaging-and-releasing-data) describes
 | 
			
		||||
solutions for common data export scenarios.
 | 
			
		||||
 | 
			
		||||
["Processing Data"](#packaging-and-releasing-data) describes solutions for
 | 
			
		||||
common workbook processing and manipulation scenarios.
 | 
			
		||||
 | 
			
		||||
["Utility Functions"](#utility-functions) details utility functions for
 | 
			
		||||
translating JSON Arrays and other common JS structures into worksheet objects.
 | 
			
		||||
 | 
			
		||||
### The Zen of SheetJS
 | 
			
		||||
 | 
			
		||||
_Data processing should fit in any workflow_
 | 
			
		||||
@ -56,15 +68,6 @@ The library does not impose a separate lifecycle.  It fits nicely in websites
 | 
			
		||||
and apps built using any framework.  The plain JS data objects play nice with
 | 
			
		||||
Web Workers and future APIs.
 | 
			
		||||
 | 
			
		||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
 | 
			
		||||
solutions for common data import scenarios.
 | 
			
		||||
 | 
			
		||||
["Writing Workbooks"](#writing-workbooks) describes solutions for common data
 | 
			
		||||
export scenarios involving actual spreadsheet files.
 | 
			
		||||
 | 
			
		||||
["Utility Functions"](#utility-functions) details utility functions for
 | 
			
		||||
translating JSON Arrays and other common JS structures into worksheet objects.
 | 
			
		||||
 | 
			
		||||
_JavaScript is a powerful language for data processing_
 | 
			
		||||
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
 | 
			
		||||
 | 
			
		||||
@ -40,3 +40,9 @@ The [`demos` directory](demos/) includes sample projects for:
 | 
			
		||||
 | 
			
		||||
Other examples are included in the [showcase](demos/showcase/).
 | 
			
		||||
 | 
			
		||||
<https://sheetjs.com/demos/modify.html> shows a complete example of reading,
 | 
			
		||||
modifying, and writing files.
 | 
			
		||||
 | 
			
		||||
<https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line
 | 
			
		||||
tool included with node installations, reading spreadsheet files and exporting
 | 
			
		||||
the contents in various formats.
 | 
			
		||||
 | 
			
		||||
@ -440,3 +440,4 @@ const workbook = XLSX.read(data);
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
More detailed examples are covered in the [included demos](demos/)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
### Processing JSON and JS Data
 | 
			
		||||
 | 
			
		||||
JSON and JS data tend to represent single worksheets.  This section will use a
 | 
			
		||||
few utility functions to generate workbooks:
 | 
			
		||||
few utility functions to generate workbooks.
 | 
			
		||||
 | 
			
		||||
_Create a new Worksheet_
 | 
			
		||||
_Create a new Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var workbook = XLSX.utils.book_new();
 | 
			
		||||
@ -11,16 +11,9 @@ var workbook = XLSX.utils.book_new();
 | 
			
		||||
 | 
			
		||||
The `book_new` utility function creates an empty workbook with no worksheets.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_Append a Worksheet to a Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
 | 
			
		||||
The third argument specifies the desired worksheet name. Multiple worksheets can
 | 
			
		||||
be added to a workbook by calling the function multiple times.
 | 
			
		||||
Spreadsheet software generally require at least one worksheet and enforce the
 | 
			
		||||
requirement in the user interface.  This library enforces the requirement at
 | 
			
		||||
write time, throwing errors if an empty workbook is passed to write functions.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**API**
 | 
			
		||||
@ -33,14 +26,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts);
 | 
			
		||||
 | 
			
		||||
The `aoa_to_sheet` utility function walks an "array of arrays" in row-major
 | 
			
		||||
order, generating a worksheet object.  The following snippet generates a sheet
 | 
			
		||||
with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc:
 | 
			
		||||
with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  ["A1", "B1", "C1"],
 | 
			
		||||
  ["A2", "B2", "C2"],
 | 
			
		||||
  ["A3", "B3", "C3"]
 | 
			
		||||
])
 | 
			
		||||
]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
 | 
			
		||||
 | 
			
		||||
@ -1,38 +1,54 @@
 | 
			
		||||
## Working with the Workbook
 | 
			
		||||
## Processing Data
 | 
			
		||||
 | 
			
		||||
The full object format is described later in this README.
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
 | 
			
		||||
representation of the core concepts of a workbook.  The utility functions work
 | 
			
		||||
with the object representation and are intended to handle common use cases.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Reading a specific cell </b> (click to show)</summary>
 | 
			
		||||
### Modifying Workbook Structure
 | 
			
		||||
 | 
			
		||||
This example extracts the value stored in cell A1 from the first worksheet:
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Append a Worksheet to a Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var first_sheet_name = workbook.SheetNames[0];
 | 
			
		||||
var address_of_cell = 'A1';
 | 
			
		||||
 | 
			
		||||
/* Get worksheet */
 | 
			
		||||
var worksheet = workbook.Sheets[first_sheet_name];
 | 
			
		||||
 | 
			
		||||
/* Find desired cell */
 | 
			
		||||
var desired_cell = worksheet[address_of_cell];
 | 
			
		||||
 | 
			
		||||
/* Get the value */
 | 
			
		||||
var desired_value = (desired_cell ? desired_cell.v : undefined);
 | 
			
		||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
 | 
			
		||||
The third argument specifies the desired worksheet name. Multiple worksheets can
 | 
			
		||||
be added to a workbook by calling the function multiple times.
 | 
			
		||||
 | 
			
		||||
_List the Worksheet names in tab order_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var wsnames = workbook.SheetNames;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `SheetNames` property of the workbook object is a list of the worksheet
 | 
			
		||||
names in "tab order".  API functions will look at this array.
 | 
			
		||||
 | 
			
		||||
_Replace a Worksheet in place_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
workbook.Sheets[sheet_name] = new_worksheet;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `Sheets` property of the workbook object is an object whose keys are names
 | 
			
		||||
and whose values are worksheet objects.  By reassigning to a property of the
 | 
			
		||||
`Sheets` object, the worksheet object can be changed without disrupting the
 | 
			
		||||
rest of the worksheet structure.
 | 
			
		||||
 | 
			
		||||
**Examples**
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Adding a new worksheet to a workbook</b> (click to show)</summary>
 | 
			
		||||
  <summary><b>Add a new worksheet to a workbook</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a
 | 
			
		||||
sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook:
 | 
			
		||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input).
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var ws_name = "SheetJS";
 | 
			
		||||
 | 
			
		||||
/* make worksheet */
 | 
			
		||||
/* Create worksheet */
 | 
			
		||||
var ws_data = [
 | 
			
		||||
  [ "S", "h", "e", "e", "t", "J", "S" ],
 | 
			
		||||
  [  1 ,  2 ,  3 ,  4 ,  5 ]
 | 
			
		||||
@ -45,39 +61,58 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name);
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Creating a new workbook from scratch</b> (click to show)</summary>
 | 
			
		||||
### Modifying Cell Values
 | 
			
		||||
 | 
			
		||||
The workbook object contains a `SheetNames` array of names and a `Sheets` object
 | 
			
		||||
mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function
 | 
			
		||||
creates a new workbook object:
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Modify a single cell value in a worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/* create a new blank workbook */
 | 
			
		||||
var wb = XLSX.utils.book_new();
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The new workbook is blank and contains no worksheets. The write functions will
 | 
			
		||||
error if the workbook is empty.
 | 
			
		||||
_Modify multiple cell values in a worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, aoa, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `sheet_add_aoa` utility function modifies cell values in a worksheet.  The
 | 
			
		||||
first argument is the worksheet object.  The second argument is an array of
 | 
			
		||||
arrays of values.  The `origin` key of the third argument controls where cells
 | 
			
		||||
will be written.  The following snippet sets `B3=1` and `E5="abc"`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [
 | 
			
		||||
  [1],                             // <-- Write 1 to cell B3
 | 
			
		||||
  ,                                // <-- Do nothing in row 4
 | 
			
		||||
  [/*B5*/, /*C5*/, /*D5*/, "abc"]  // <-- Write "abc" to cell E5
 | 
			
		||||
], { origin: "B3" });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
 | 
			
		||||
optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
**Examples**
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Appending rows to a worksheet</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
The special origin value `-1` instructs `sheet_add_aoa` to start in column A of
 | 
			
		||||
the row after the last row in the range, appending the data:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [
 | 
			
		||||
  ["first row after data", 1],
 | 
			
		||||
  ["second row after data", 2]
 | 
			
		||||
], { origin: -1 });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Parsing and Writing Examples
 | 
			
		||||
### Modifying Other Worksheet / Workbook / Cell Properties
 | 
			
		||||
 | 
			
		||||
- <https://sheetjs.com/demos/modify.html> read + modify + write files
 | 
			
		||||
 | 
			
		||||
- <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node
 | 
			
		||||
 | 
			
		||||
The node version installs a command line tool `xlsx` which can read spreadsheet
 | 
			
		||||
files and output the contents in various formats.  The source is available at
 | 
			
		||||
`xlsx.njs` in the bin directory.
 | 
			
		||||
 | 
			
		||||
Some helper functions in `XLSX.utils` generate different views of the sheets:
 | 
			
		||||
 | 
			
		||||
- `XLSX.utils.sheet_to_csv` generates CSV
 | 
			
		||||
- `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text
 | 
			
		||||
- `XLSX.utils.sheet_to_html` generates HTML
 | 
			
		||||
- `XLSX.utils.sheet_to_json` generates an array of objects
 | 
			
		||||
- `XLSX.utils.sheet_to_formulae` generates a list of formulae
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes
 | 
			
		||||
the object structures in greater detail.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -255,3 +255,42 @@ The [`vuejs` demo](demos/vue) includes more React examples.
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### Generating Single-Worksheet Snapshots
 | 
			
		||||
 | 
			
		||||
The `sheet_to_*` functions accept a worksheet object.
 | 
			
		||||
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Generate a CSV from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var csv = XLSX.utils.sheet_to_csv(worksheet, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type.
 | 
			
		||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
 | 
			
		||||
function and the optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
_Generate "Text" from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var txt = XLSX.utils.sheet_to_txt(worksheet, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type.
 | 
			
		||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
 | 
			
		||||
function and the optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
_Generate a list of formulae from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var fmla = XLSX.utils.sheet_to_formulae(worksheet);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot generates an array of entries representing the embedded formulae.
 | 
			
		||||
Array formulae are rendered in the form `range=formula` while plain cells are
 | 
			
		||||
rendered in the form `cell=formula or value`.  String literals are prefixed with
 | 
			
		||||
an apostrophe `'`, consistent with Excel's formula bar display.
 | 
			
		||||
 | 
			
		||||
["Formulae Output"](#formulae-output) describes the function in more detail.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ Cell objects are plain JS objects with keys and values following the convention:
 | 
			
		||||
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
 | 
			
		||||
| `f` | cell formula encoded as an A1-style string (if applicable)             |
 | 
			
		||||
| `F` | range of enclosing array if formula is array formula (if applicable)   |
 | 
			
		||||
| `D` | if true, array formula is dynamic (if applicable)                      |
 | 
			
		||||
| `r` | rich text encoding (if applicable)                                     |
 | 
			
		||||
| `h` | HTML rendering of the rich text (if applicable)                        |
 | 
			
		||||
| `c` | comments associated with the cell                                      |
 | 
			
		||||
 | 
			
		||||
@ -6,79 +6,7 @@ Even though some formats store formulae with a leading equal sign, CSF formulae
 | 
			
		||||
do not start with `=`.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Representation of A1=1, A2=2, A3=A1+A2</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
{
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:1 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', v:3, f:'A1+A2' }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
Shared formulae are decompressed and each cell has the formula corresponding to
 | 
			
		||||
its cell.  Writers generally do not attempt to generate shared formulae.
 | 
			
		||||
 | 
			
		||||
Cells with formula entries but no value will be serialized in a way that Excel
 | 
			
		||||
and other spreadsheet tools will recognize.  This library will not automatically
 | 
			
		||||
compute formula results!  For example, to compute `BESSELJ` in a worksheet:
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Formula without known value</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
{
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:3.14159 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', f:'BESSELJ(A1,A2)' }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
**Array Formulae**
 | 
			
		||||
 | 
			
		||||
Array formulae are stored in the top-left cell of the array block.  All cells
 | 
			
		||||
of an array formula have a `F` field corresponding to the range.  A single-cell
 | 
			
		||||
formula can be distinguished from a plain formula by the presence of `F` field.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Array Formula examples</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For a multi-cell array formula, every cell has the same array range but only the
 | 
			
		||||
first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
 | 
			
		||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
Utilities and writers are expected to check for the presence of a `F` field and
 | 
			
		||||
ignore any possible formula element `f` in cells other than the starting cell.
 | 
			
		||||
They are not expected to perform validation of the formulae!
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Formula Output Utility Function</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
The `sheet_to_formulae` method generates one line per formula or array formula.
 | 
			
		||||
Array formulae are rendered in the form `range=formula` while plain cells are
 | 
			
		||||
rendered in the form `cell=formula or value`.  Note that string literals are
 | 
			
		||||
prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b>Formulae File Format Details</b> (click to show)</summary>
 | 
			
		||||
  <summary><b>Formulae File Format Support</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
| Storage Representation | Formats                  | Read  | Write |
 | 
			
		||||
|:-----------------------|:-------------------------|:-----:|:-----:|
 | 
			
		||||
@ -92,5 +20,271 @@ Since Excel prohibits named cells from colliding with names of A1 or RC style
 | 
			
		||||
cell references, a (not-so-simple) regex conversion is possible.  BIFF Parsed
 | 
			
		||||
formulae and Lotus Parsed formulae have to be explicitly unwound.  OpenFormula
 | 
			
		||||
formulae can be converted with regular expressions.
 | 
			
		||||
 | 
			
		||||
Shared formulae are decompressed and each cell has the formula corresponding to
 | 
			
		||||
its cell.  Writers generally do not attempt to generate shared formulae.
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
**Single-Cell Formulae**
 | 
			
		||||
 | 
			
		||||
For simple formulae, the `f` key of the desired cell can be set to the actual
 | 
			
		||||
formula text.  This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = {
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:1 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', v:3, f:'A1+A2' }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Utilities like `aoa_to_sheet` will accept cell objects in lieu of values:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  [ 1 ], // A1
 | 
			
		||||
  [ 2 ], // A2
 | 
			
		||||
  [ {t: "n", v: 3, f: "A1+A2"} ] // A3
 | 
			
		||||
]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Cells with formula entries but no value will be serialized in a way that Excel
 | 
			
		||||
and other spreadsheet tools will recognize.  This library will not automatically
 | 
			
		||||
compute formula results!  For example, the following worksheet will include the
 | 
			
		||||
`BESSELJ` function but the result will not be available in JavaScript:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  [ 3.14159, 2 ], // Row "1"
 | 
			
		||||
  [ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro)
 | 
			
		||||
offers a formula calculator component for evaluating expressions, updating
 | 
			
		||||
values and dependent cells, and refreshing entire workbooks.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**Array Formulae**
 | 
			
		||||
 | 
			
		||||
_Assign an array formula_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Array formulae are stored in the top-left cell of the array block.  All cells
 | 
			
		||||
of an array formula have a `F` field corresponding to the range.  A single-cell
 | 
			
		||||
formula can be distinguished from a plain formula by the presence of `F` field.
 | 
			
		||||
 | 
			
		||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)");
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For a multi-cell array formula, every cell has the same array range but only the
 | 
			
		||||
first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3");
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
 | 
			
		||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Utilities and writers are expected to check for the presence of a `F` field and
 | 
			
		||||
ignore any possible formula element `f` in cells other than the starting cell.
 | 
			
		||||
They are not expected to perform validation of the formulae!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**Dynamic Array Formulae**
 | 
			
		||||
 | 
			
		||||
_Assign a dynamic array formula_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
 | 
			
		||||
file formats.  They are represented like normal array formulae but have special
 | 
			
		||||
cell metadata indicating that the formula should be allowed to adjust the range.
 | 
			
		||||
 | 
			
		||||
An array formula can be marked as dynamic by setting the cell's `D` property to
 | 
			
		||||
true.  The `F` range is expected but can be the set to the current cell:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Localization with Function Names**
 | 
			
		||||
 | 
			
		||||
SheetJS operates at the file level.  Excel stores formula expressions using the
 | 
			
		||||
English (United States) function names.  For non-English users, Excel uses a
 | 
			
		||||
localized set of function names.
 | 
			
		||||
 | 
			
		||||
For example, when the computer language and region is set to French (France),
 | 
			
		||||
Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function.  However,
 | 
			
		||||
in the actual file, Excel stores `SUM(A1:C3)`.
 | 
			
		||||
 | 
			
		||||
**Prefixed "Future Functions"**
 | 
			
		||||
 | 
			
		||||
Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when
 | 
			
		||||
stored in files.  When writing formula expressions using these functions, the
 | 
			
		||||
prefix is required for maximal compatibility:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// Broadest compatibility
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
 | 
			
		||||
 | 
			
		||||
// Can cause errors in spreadsheet software
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When reading a file, the `xlfn` option preserves the prefixes.
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
  <summary><b> Functions requiring `_xlfn.` prefix</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
This list is growing with each Excel release.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
ACOT
 | 
			
		||||
ACOTH
 | 
			
		||||
AGGREGATE
 | 
			
		||||
ARABIC
 | 
			
		||||
BASE
 | 
			
		||||
BETA.DIST
 | 
			
		||||
BETA.INV
 | 
			
		||||
BINOM.DIST
 | 
			
		||||
BINOM.DIST.RANGE
 | 
			
		||||
BINOM.INV
 | 
			
		||||
BITAND
 | 
			
		||||
BITLSHIFT
 | 
			
		||||
BITOR
 | 
			
		||||
BITRSHIFT
 | 
			
		||||
BITXOR
 | 
			
		||||
BYCOL
 | 
			
		||||
BYROW
 | 
			
		||||
CEILING.MATH
 | 
			
		||||
CEILING.PRECISE
 | 
			
		||||
CHISQ.DIST
 | 
			
		||||
CHISQ.DIST.RT
 | 
			
		||||
CHISQ.INV
 | 
			
		||||
CHISQ.INV.RT
 | 
			
		||||
CHISQ.TEST
 | 
			
		||||
COMBINA
 | 
			
		||||
CONFIDENCE.NORM
 | 
			
		||||
CONFIDENCE.T
 | 
			
		||||
COT
 | 
			
		||||
COTH
 | 
			
		||||
COVARIANCE.P
 | 
			
		||||
COVARIANCE.S
 | 
			
		||||
CSC
 | 
			
		||||
CSCH
 | 
			
		||||
DAYS
 | 
			
		||||
DECIMAL
 | 
			
		||||
ERF.PRECISE
 | 
			
		||||
ERFC.PRECISE
 | 
			
		||||
EXPON.DIST
 | 
			
		||||
F.DIST
 | 
			
		||||
F.DIST.RT
 | 
			
		||||
F.INV
 | 
			
		||||
F.INV.RT
 | 
			
		||||
F.TEST
 | 
			
		||||
FIELDVALUE
 | 
			
		||||
FILTERXML
 | 
			
		||||
FLOOR.MATH
 | 
			
		||||
FLOOR.PRECISE
 | 
			
		||||
FORMULATEXT
 | 
			
		||||
GAMMA
 | 
			
		||||
GAMMA.DIST
 | 
			
		||||
GAMMA.INV
 | 
			
		||||
GAMMALN.PRECISE
 | 
			
		||||
GAUSS
 | 
			
		||||
HYPGEOM.DIST
 | 
			
		||||
IFNA
 | 
			
		||||
IMCOSH
 | 
			
		||||
IMCOT
 | 
			
		||||
IMCSC
 | 
			
		||||
IMCSCH
 | 
			
		||||
IMSEC
 | 
			
		||||
IMSECH
 | 
			
		||||
IMSINH
 | 
			
		||||
IMTAN
 | 
			
		||||
ISFORMULA
 | 
			
		||||
ISOMITTED
 | 
			
		||||
ISOWEEKNUM
 | 
			
		||||
LAMBDA
 | 
			
		||||
LET
 | 
			
		||||
LOGNORM.DIST
 | 
			
		||||
LOGNORM.INV
 | 
			
		||||
MAKEARRAY
 | 
			
		||||
MAP
 | 
			
		||||
MODE.MULT
 | 
			
		||||
MODE.SNGL
 | 
			
		||||
MUNIT
 | 
			
		||||
NEGBINOM.DIST
 | 
			
		||||
NORM.DIST
 | 
			
		||||
NORM.INV
 | 
			
		||||
NORM.S.DIST
 | 
			
		||||
NORM.S.INV
 | 
			
		||||
NUMBERVALUE
 | 
			
		||||
PDURATION
 | 
			
		||||
PERCENTILE.EXC
 | 
			
		||||
PERCENTILE.INC
 | 
			
		||||
PERCENTRANK.EXC
 | 
			
		||||
PERCENTRANK.INC
 | 
			
		||||
PERMUTATIONA
 | 
			
		||||
PHI
 | 
			
		||||
POISSON.DIST
 | 
			
		||||
QUARTILE.EXC
 | 
			
		||||
QUARTILE.INC
 | 
			
		||||
QUERYSTRING
 | 
			
		||||
RANDARRAY
 | 
			
		||||
RANK.AVG
 | 
			
		||||
RANK.EQ
 | 
			
		||||
REDUCE
 | 
			
		||||
RRI
 | 
			
		||||
SCAN
 | 
			
		||||
SEC
 | 
			
		||||
SECH
 | 
			
		||||
SEQUENCE
 | 
			
		||||
SHEET
 | 
			
		||||
SHEETS
 | 
			
		||||
SKEW.P
 | 
			
		||||
SORTBY
 | 
			
		||||
STDEV.P
 | 
			
		||||
STDEV.S
 | 
			
		||||
T.DIST
 | 
			
		||||
T.DIST.2T
 | 
			
		||||
T.DIST.RT
 | 
			
		||||
T.INV
 | 
			
		||||
T.INV.2T
 | 
			
		||||
T.TEST
 | 
			
		||||
UNICHAR
 | 
			
		||||
UNICODE
 | 
			
		||||
UNIQUE
 | 
			
		||||
VAR.P
 | 
			
		||||
VAR.S
 | 
			
		||||
WEBSERVICE
 | 
			
		||||
WEIBULL.DIST
 | 
			
		||||
XLOOKUP
 | 
			
		||||
XOR
 | 
			
		||||
Z.TEST
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								mini.lst
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								mini.lst
									
									
									
									
									
								
							@ -28,6 +28,7 @@ bits/42_sstxml.js
 | 
			
		||||
bits/46_stycommon.js
 | 
			
		||||
bits/47_styxml.js
 | 
			
		||||
bits/49_theme.js
 | 
			
		||||
misc/51_xlsxmeta.js
 | 
			
		||||
bits/53_externlink.js
 | 
			
		||||
bits/54_drawing.js
 | 
			
		||||
bits/55_vml.js
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
 | 
			
		||||
	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
 | 
			
		||||
	if(typeof Deno !== 'undefined') {
 | 
			
		||||
		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
 | 
			
		||||
		if(enc) switch(enc) {
 | 
			
		||||
		if(enc && typeof payload == "string") switch(enc) {
 | 
			
		||||
			case "utf8": payload = new TextEncoder(enc).encode(payload); break;
 | 
			
		||||
			case "binary": payload = s2ab(payload); break;
 | 
			
		||||
			/* TODO: binary equivalent */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										63
									
								
								misc/51_xlsxmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										63
									
								
								misc/51_xlsxmeta.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
function parse_xlmeta_xml(data, name, opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  if (!data)
 | 
			
		||||
    return out;
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  data.replace(tagregex, function(x, idx) {
 | 
			
		||||
    var y = parsexmltag(x);
 | 
			
		||||
    switch (strip_ns(y[0])) {
 | 
			
		||||
      case "<?xml":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadata":
 | 
			
		||||
      case "</metadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataTypes":
 | 
			
		||||
      case "</metadataTypes>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataType":
 | 
			
		||||
        out.Types.push({ name: y.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case "<futureMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</futureMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<rc":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</rc>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<cellMetadata":
 | 
			
		||||
      case "</cellMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<valueMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</valueMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<extLst":
 | 
			
		||||
      case "<extLst>":
 | 
			
		||||
      case "</extLst>":
 | 
			
		||||
      case "<extLst/>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<ext":
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case "</ext>":
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (!pass && opts.WTF)
 | 
			
		||||
          throw new Error("unrecognized " + y[0] + " in metadata");
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_xml() {
 | 
			
		||||
  var o = [XML_HEADER];
 | 
			
		||||
  o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>');
 | 
			
		||||
  return o.join("");
 | 
			
		||||
}
 | 
			
		||||
@ -24,10 +24,8 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Table of Contents
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -42,14 +40,17 @@ port calculations to web apps; automate common spreadsheet tasks, and much more!
 | 
			
		||||
  * [Parsing Workbooks](#parsing-workbooks)
 | 
			
		||||
  * [Processing JSON and JS Data](#processing-json-and-js-data)
 | 
			
		||||
  * [Processing HTML Tables](#processing-html-tables)
 | 
			
		||||
- [Working with the Workbook](#working-with-the-workbook)
 | 
			
		||||
  * [Parsing and Writing Examples](#parsing-and-writing-examples)
 | 
			
		||||
- [Processing Data](#processing-data)
 | 
			
		||||
  * [Modifying Workbook Structure](#modifying-workbook-structure)
 | 
			
		||||
  * [Modifying Cell Values](#modifying-cell-values)
 | 
			
		||||
  * [Modifying Other Worksheet / Workbook / Cell Properties](#modifying-other-worksheet--workbook--cell-properties)
 | 
			
		||||
- [Packaging and Releasing Data](#packaging-and-releasing-data)
 | 
			
		||||
  * [Writing Workbooks](#writing-workbooks)
 | 
			
		||||
  * [Writing Examples](#writing-examples)
 | 
			
		||||
  * [Streaming Write](#streaming-write)
 | 
			
		||||
  * [Generating JSON and JS Data](#generating-json-and-js-data)
 | 
			
		||||
  * [Generating HTML Tables](#generating-html-tables)
 | 
			
		||||
  * [Generating Single-Worksheet Snapshots](#generating-single-worksheet-snapshots)
 | 
			
		||||
- [Interface](#interface)
 | 
			
		||||
  * [Parsing functions](#parsing-functions)
 | 
			
		||||
  * [Writing functions](#writing-functions)
 | 
			
		||||
@ -140,10 +141,11 @@ For example, `unpkg` makes the latest version available at:
 | 
			
		||||
 | 
			
		||||
The complete single-file version is generated at `dist/xlsx.full.min.js`
 | 
			
		||||
 | 
			
		||||
`dist/xlsx.core.min.js` omits codepage library (no support for XLS encodings)
 | 
			
		||||
 | 
			
		||||
A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build:
 | 
			
		||||
- codepage library skipped (no support for XLS encodings)
 | 
			
		||||
- XLSX compression option not currently available
 | 
			
		||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003
 | 
			
		||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers
 | 
			
		||||
- node stream utils removed
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -303,6 +305,18 @@ and approaches for steps 1 and 5.
 | 
			
		||||
 | 
			
		||||
Utility functions help with step 3.
 | 
			
		||||
 | 
			
		||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
 | 
			
		||||
solutions for common data import scenarios.
 | 
			
		||||
 | 
			
		||||
["Packaging and Releasing Data"](#packaging-and-releasing-data) describes
 | 
			
		||||
solutions for common data export scenarios.
 | 
			
		||||
 | 
			
		||||
["Processing Data"](#packaging-and-releasing-data) describes solutions for
 | 
			
		||||
common workbook processing and manipulation scenarios.
 | 
			
		||||
 | 
			
		||||
["Utility Functions"](#utility-functions) details utility functions for
 | 
			
		||||
translating JSON Arrays and other common JS structures into worksheet objects.
 | 
			
		||||
 | 
			
		||||
### The Zen of SheetJS
 | 
			
		||||
 | 
			
		||||
_Data processing should fit in any workflow_
 | 
			
		||||
@ -311,15 +325,6 @@ The library does not impose a separate lifecycle.  It fits nicely in websites
 | 
			
		||||
and apps built using any framework.  The plain JS data objects play nice with
 | 
			
		||||
Web Workers and future APIs.
 | 
			
		||||
 | 
			
		||||
["Acquiring and Extracting Data"](#acquiring-and-extracting-data) describes
 | 
			
		||||
solutions for common data import scenarios.
 | 
			
		||||
 | 
			
		||||
["Writing Workbooks"](#writing-workbooks) describes solutions for common data
 | 
			
		||||
export scenarios involving actual spreadsheet files.
 | 
			
		||||
 | 
			
		||||
["Utility Functions"](#utility-functions) details utility functions for
 | 
			
		||||
translating JSON Arrays and other common JS structures into worksheet objects.
 | 
			
		||||
 | 
			
		||||
_JavaScript is a powerful language for data processing_
 | 
			
		||||
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
 | 
			
		||||
@ -559,6 +564,12 @@ The [`demos` directory](demos/) includes sample projects for:
 | 
			
		||||
 | 
			
		||||
Other examples are included in the [showcase](demos/showcase/).
 | 
			
		||||
 | 
			
		||||
<https://sheetjs.com/demos/modify.html> shows a complete example of reading,
 | 
			
		||||
modifying, and writing files.
 | 
			
		||||
 | 
			
		||||
<https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> is the command-line
 | 
			
		||||
tool included with node installations, reading spreadsheet files and exporting
 | 
			
		||||
the contents in various formats.
 | 
			
		||||
## Acquiring and Extracting Data
 | 
			
		||||
 | 
			
		||||
### Parsing Workbooks
 | 
			
		||||
@ -962,12 +973,13 @@ const workbook = XLSX.read(data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
More detailed examples are covered in the [included demos](demos/)
 | 
			
		||||
 | 
			
		||||
### Processing JSON and JS Data
 | 
			
		||||
 | 
			
		||||
JSON and JS data tend to represent single worksheets.  This section will use a
 | 
			
		||||
few utility functions to generate workbooks:
 | 
			
		||||
few utility functions to generate workbooks.
 | 
			
		||||
 | 
			
		||||
_Create a new Worksheet_
 | 
			
		||||
_Create a new Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var workbook = XLSX.utils.book_new();
 | 
			
		||||
@ -975,16 +987,9 @@ var workbook = XLSX.utils.book_new();
 | 
			
		||||
 | 
			
		||||
The `book_new` utility function creates an empty workbook with no worksheets.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
_Append a Worksheet to a Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
 | 
			
		||||
The third argument specifies the desired worksheet name. Multiple worksheets can
 | 
			
		||||
be added to a workbook by calling the function multiple times.
 | 
			
		||||
Spreadsheet software generally require at least one worksheet and enforce the
 | 
			
		||||
requirement in the user interface.  This library enforces the requirement at
 | 
			
		||||
write time, throwing errors if an empty workbook is passed to write functions.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**API**
 | 
			
		||||
@ -997,14 +1002,14 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa, opts);
 | 
			
		||||
 | 
			
		||||
The `aoa_to_sheet` utility function walks an "array of arrays" in row-major
 | 
			
		||||
order, generating a worksheet object.  The following snippet generates a sheet
 | 
			
		||||
with cell `A1` set to the string `A1`, cell `B1` set to `B2`, etc:
 | 
			
		||||
with cell `A1` set to the string `A1`, cell `B1` set to `B1`, etc:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  ["A1", "B1", "C1"],
 | 
			
		||||
  ["A2", "B2", "C2"],
 | 
			
		||||
  ["A3", "B3", "C3"]
 | 
			
		||||
])
 | 
			
		||||
]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
 | 
			
		||||
@ -1284,36 +1289,55 @@ const workbook = XLSX.utils.table_to_book(doc);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## Working with the Workbook
 | 
			
		||||
## Processing Data
 | 
			
		||||
 | 
			
		||||
The full object format is described later in this README.
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) is a simple object
 | 
			
		||||
representation of the core concepts of a workbook.  The utility functions work
 | 
			
		||||
with the object representation and are intended to handle common use cases.
 | 
			
		||||
 | 
			
		||||
### Modifying Workbook Structure
 | 
			
		||||
 | 
			
		||||
This example extracts the value stored in cell A1 from the first worksheet:
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Append a Worksheet to a Workbook_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var first_sheet_name = workbook.SheetNames[0];
 | 
			
		||||
var address_of_cell = 'A1';
 | 
			
		||||
 | 
			
		||||
/* Get worksheet */
 | 
			
		||||
var worksheet = workbook.Sheets[first_sheet_name];
 | 
			
		||||
 | 
			
		||||
/* Find desired cell */
 | 
			
		||||
var desired_cell = worksheet[address_of_cell];
 | 
			
		||||
 | 
			
		||||
/* Get the value */
 | 
			
		||||
var desired_value = (desired_cell ? desired_cell.v : undefined);
 | 
			
		||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheet_name);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `book_append_sheet` utility function appends a worksheet to the workbook.
 | 
			
		||||
The third argument specifies the desired worksheet name. Multiple worksheets can
 | 
			
		||||
be added to a workbook by calling the function multiple times.
 | 
			
		||||
 | 
			
		||||
_List the Worksheet names in tab order_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var wsnames = workbook.SheetNames;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `SheetNames` property of the workbook object is a list of the worksheet
 | 
			
		||||
names in "tab order".  API functions will look at this array.
 | 
			
		||||
 | 
			
		||||
_Replace a Worksheet in place_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
workbook.Sheets[sheet_name] = new_worksheet;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `Sheets` property of the workbook object is an object whose keys are names
 | 
			
		||||
and whose values are worksheet objects.  By reassigning to a property of the
 | 
			
		||||
`Sheets` object, the worksheet object can be changed without disrupting the
 | 
			
		||||
rest of the worksheet structure.
 | 
			
		||||
 | 
			
		||||
**Examples**
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input) to make a
 | 
			
		||||
sheet and `XLSX.utils.book_append_sheet` to append the sheet to the workbook:
 | 
			
		||||
This example uses [`XLSX.utils.aoa_to_sheet`](#array-of-arrays-input).
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var ws_name = "SheetJS";
 | 
			
		||||
 | 
			
		||||
/* make worksheet */
 | 
			
		||||
/* Create worksheet */
 | 
			
		||||
var ws_data = [
 | 
			
		||||
  [ "S", "h", "e", "e", "t", "J", "S" ],
 | 
			
		||||
  [  1 ,  2 ,  3 ,  4 ,  5 ]
 | 
			
		||||
@ -1325,38 +1349,57 @@ XLSX.utils.book_append_sheet(wb, ws, ws_name);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Modifying Cell Values
 | 
			
		||||
 | 
			
		||||
The workbook object contains a `SheetNames` array of names and a `Sheets` object
 | 
			
		||||
mapping sheet names to sheet objects. The `XLSX.utils.book_new` utility function
 | 
			
		||||
creates a new workbook object:
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Modify a single cell value in a worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
/* create a new blank workbook */
 | 
			
		||||
var wb = XLSX.utils.book_new();
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [[new_value]], { origin: address });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The new workbook is blank and contains no worksheets. The write functions will
 | 
			
		||||
error if the workbook is empty.
 | 
			
		||||
_Modify multiple cell values in a worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, aoa, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `sheet_add_aoa` utility function modifies cell values in a worksheet.  The
 | 
			
		||||
first argument is the worksheet object.  The second argument is an array of
 | 
			
		||||
arrays of values.  The `origin` key of the third argument controls where cells
 | 
			
		||||
will be written.  The following snippet sets `B3=1` and `E5="abc"`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [
 | 
			
		||||
  [1],                             // <-- Write 1 to cell B3
 | 
			
		||||
  ,                                // <-- Do nothing in row 4
 | 
			
		||||
  [/*B5*/, /*C5*/, /*D5*/, "abc"]  // <-- Write "abc" to cell E5
 | 
			
		||||
], { origin: "B3" });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
["Array of Arrays Input"](#array-of-arrays-input) describes the function and the
 | 
			
		||||
optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
**Examples**
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The special origin value `-1` instructs `sheet_add_aoa` to start in column A of
 | 
			
		||||
the row after the last row in the range, appending the data:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_add_aoa(worksheet, [
 | 
			
		||||
  ["first row after data", 1],
 | 
			
		||||
  ["second row after data", 2]
 | 
			
		||||
], { origin: -1 });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Parsing and Writing Examples
 | 
			
		||||
### Modifying Other Worksheet / Workbook / Cell Properties
 | 
			
		||||
 | 
			
		||||
- <https://sheetjs.com/demos/modify.html> read + modify + write files
 | 
			
		||||
 | 
			
		||||
- <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node
 | 
			
		||||
 | 
			
		||||
The node version installs a command line tool `xlsx` which can read spreadsheet
 | 
			
		||||
files and output the contents in various formats.  The source is available at
 | 
			
		||||
`xlsx.njs` in the bin directory.
 | 
			
		||||
 | 
			
		||||
Some helper functions in `XLSX.utils` generate different views of the sheets:
 | 
			
		||||
 | 
			
		||||
- `XLSX.utils.sheet_to_csv` generates CSV
 | 
			
		||||
- `XLSX.utils.sheet_to_txt` generates UTF16 Formatted Text
 | 
			
		||||
- `XLSX.utils.sheet_to_html` generates HTML
 | 
			
		||||
- `XLSX.utils.sheet_to_json` generates an array of objects
 | 
			
		||||
- `XLSX.utils.sheet_to_formulae` generates a list of formulae
 | 
			
		||||
The ["Common Spreadsheet Format"](#common-spreadsheet-format) section describes
 | 
			
		||||
the object structures in greater detail.
 | 
			
		||||
 | 
			
		||||
## Packaging and Releasing Data
 | 
			
		||||
 | 
			
		||||
@ -1832,6 +1875,45 @@ const S5SComponent = {
 | 
			
		||||
The [`vuejs` demo](demos/vue) includes more React examples.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### Generating Single-Worksheet Snapshots
 | 
			
		||||
 | 
			
		||||
The `sheet_to_*` functions accept a worksheet object.
 | 
			
		||||
 | 
			
		||||
**API**
 | 
			
		||||
 | 
			
		||||
_Generate a CSV from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var csv = XLSX.utils.sheet_to_csv(worksheet, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot is designed to replicate the "CSV UTF8 (`.csv`)" output type.
 | 
			
		||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
 | 
			
		||||
function and the optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
_Generate "Text" from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var txt = XLSX.utils.sheet_to_txt(worksheet, opts);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot is designed to replicate the "UTF16 Text (`.txt`)" output type.
 | 
			
		||||
["Delimiter-Separated Output"](#delimiter-separated-output) describes the
 | 
			
		||||
function and the optional `opts` argument in more detail.
 | 
			
		||||
 | 
			
		||||
_Generate a list of formulae from a single worksheet_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var fmla = XLSX.utils.sheet_to_formulae(worksheet);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This snapshot generates an array of entries representing the embedded formulae.
 | 
			
		||||
Array formulae are rendered in the form `range=formula` while plain cells are
 | 
			
		||||
rendered in the form `cell=formula or value`.  String literals are prefixed with
 | 
			
		||||
an apostrophe `'`, consistent with Excel's formula bar display.
 | 
			
		||||
 | 
			
		||||
["Formulae Output"](#formulae-output) describes the function in more detail.
 | 
			
		||||
 | 
			
		||||
## Interface
 | 
			
		||||
 | 
			
		||||
`XLSX` is the exposed variable in the browser and the exported node variable
 | 
			
		||||
@ -1934,6 +2016,7 @@ Cell objects are plain JS objects with keys and values following the convention:
 | 
			
		||||
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
 | 
			
		||||
| `f` | cell formula encoded as an A1-style string (if applicable)             |
 | 
			
		||||
| `F` | range of enclosing array if formula is array formula (if applicable)   |
 | 
			
		||||
| `D` | if true, array formula is dynamic (if applicable)                      |
 | 
			
		||||
| `r` | rich text encoding (if applicable)                                     |
 | 
			
		||||
| `h` | HTML rendering of the rich text (if applicable)                        |
 | 
			
		||||
| `c` | comments associated with the cell                                      |
 | 
			
		||||
@ -2261,66 +2344,6 @@ Even though some formats store formulae with a leading equal sign, CSF formulae
 | 
			
		||||
do not start with `=`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
{
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:1 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', v:3, f:'A1+A2' }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Shared formulae are decompressed and each cell has the formula corresponding to
 | 
			
		||||
its cell.  Writers generally do not attempt to generate shared formulae.
 | 
			
		||||
 | 
			
		||||
Cells with formula entries but no value will be serialized in a way that Excel
 | 
			
		||||
and other spreadsheet tools will recognize.  This library will not automatically
 | 
			
		||||
compute formula results!  For example, to compute `BESSELJ` in a worksheet:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
{
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:3.14159 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', f:'BESSELJ(A1,A2)' }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Array Formulae**
 | 
			
		||||
 | 
			
		||||
Array formulae are stored in the top-left cell of the array block.  All cells
 | 
			
		||||
of an array formula have a `F` field corresponding to the range.  A single-cell
 | 
			
		||||
formula can be distinguished from a plain formula by the presence of `F` field.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For a multi-cell array formula, every cell has the same array range but only the
 | 
			
		||||
first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
 | 
			
		||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Utilities and writers are expected to check for the presence of a `F` field and
 | 
			
		||||
ignore any possible formula element `f` in cells other than the starting cell.
 | 
			
		||||
They are not expected to perform validation of the formulae!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The `sheet_to_formulae` method generates one line per formula or array formula.
 | 
			
		||||
Array formulae are rendered in the form `range=formula` while plain cells are
 | 
			
		||||
rendered in the form `cell=formula or value`.  Note that string literals are
 | 
			
		||||
prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| Storage Representation | Formats                  | Read  | Write |
 | 
			
		||||
|:-----------------------|:-------------------------|:-----:|:-----:|
 | 
			
		||||
| A1-style strings       | XLSX                     |   ✔   |   ✔   |
 | 
			
		||||
@ -2334,6 +2357,269 @@ cell references, a (not-so-simple) regex conversion is possible.  BIFF Parsed
 | 
			
		||||
formulae and Lotus Parsed formulae have to be explicitly unwound.  OpenFormula
 | 
			
		||||
formulae can be converted with regular expressions.
 | 
			
		||||
 | 
			
		||||
Shared formulae are decompressed and each cell has the formula corresponding to
 | 
			
		||||
its cell.  Writers generally do not attempt to generate shared formulae.
 | 
			
		||||
 | 
			
		||||
**Single-Cell Formulae**
 | 
			
		||||
 | 
			
		||||
For simple formulae, the `f` key of the desired cell can be set to the actual
 | 
			
		||||
formula text.  This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = {
 | 
			
		||||
  "!ref": "A1:A3",
 | 
			
		||||
  A1: { t:'n', v:1 },
 | 
			
		||||
  A2: { t:'n', v:2 },
 | 
			
		||||
  A3: { t:'n', v:3, f:'A1+A2' }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Utilities like `aoa_to_sheet` will accept cell objects in lieu of values:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  [ 1 ], // A1
 | 
			
		||||
  [ 2 ], // A2
 | 
			
		||||
  [ {t: "n", v: 3, f: "A1+A2"} ] // A3
 | 
			
		||||
]);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Cells with formula entries but no value will be serialized in a way that Excel
 | 
			
		||||
and other spreadsheet tools will recognize.  This library will not automatically
 | 
			
		||||
compute formula results!  For example, the following worksheet will include the
 | 
			
		||||
`BESSELJ` function but the result will not be available in JavaScript:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var worksheet = XLSX.utils.aoa_to_sheet([
 | 
			
		||||
  [ 3.14159, 2 ], // Row "1"
 | 
			
		||||
  [ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro)
 | 
			
		||||
offers a formula calculator component for evaluating expressions, updating
 | 
			
		||||
values and dependent cells, and refreshing entire workbooks.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**Array Formulae**
 | 
			
		||||
 | 
			
		||||
_Assign an array formula_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Array formulae are stored in the top-left cell of the array block.  All cells
 | 
			
		||||
of an array formula have a `F` field corresponding to the range.  A single-cell
 | 
			
		||||
formula can be distinguished from a plain formula by the presence of `F` field.
 | 
			
		||||
 | 
			
		||||
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)");
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For a multi-cell array formula, every cell has the same array range but only the
 | 
			
		||||
first cell specifies the formula.  Consider `D1:D3=A1:A3*B1:B3`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3");
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
 | 
			
		||||
worksheet['D2'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
worksheet['D3'] = { t:'n', F:"D1:D3" };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Utilities and writers are expected to check for the presence of a `F` field and
 | 
			
		||||
ignore any possible formula element `f` in cells other than the starting cell.
 | 
			
		||||
They are not expected to perform validation of the formulae!
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
**Dynamic Array Formulae**
 | 
			
		||||
 | 
			
		||||
_Assign a dynamic array formula_
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
 | 
			
		||||
file formats.  They are represented like normal array formulae but have special
 | 
			
		||||
cell metadata indicating that the formula should be allowed to adjust the range.
 | 
			
		||||
 | 
			
		||||
An array formula can be marked as dynamic by setting the cell's `D` property to
 | 
			
		||||
true.  The `F` range is expected but can be the set to the current cell:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// API function
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
 | 
			
		||||
 | 
			
		||||
// ... OR raw operations
 | 
			
		||||
worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Localization with Function Names**
 | 
			
		||||
 | 
			
		||||
SheetJS operates at the file level.  Excel stores formula expressions using the
 | 
			
		||||
English (United States) function names.  For non-English users, Excel uses a
 | 
			
		||||
localized set of function names.
 | 
			
		||||
 | 
			
		||||
For example, when the computer language and region is set to French (France),
 | 
			
		||||
Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function.  However,
 | 
			
		||||
in the actual file, Excel stores `SUM(A1:C3)`.
 | 
			
		||||
 | 
			
		||||
**Prefixed "Future Functions"**
 | 
			
		||||
 | 
			
		||||
Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when
 | 
			
		||||
stored in files.  When writing formula expressions using these functions, the
 | 
			
		||||
prefix is required for maximal compatibility:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// Broadest compatibility
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
 | 
			
		||||
 | 
			
		||||
// Can cause errors in spreadsheet software
 | 
			
		||||
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When reading a file, the `xlfn` option preserves the prefixes.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
This list is growing with each Excel release.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
ACOT
 | 
			
		||||
ACOTH
 | 
			
		||||
AGGREGATE
 | 
			
		||||
ARABIC
 | 
			
		||||
BASE
 | 
			
		||||
BETA.DIST
 | 
			
		||||
BETA.INV
 | 
			
		||||
BINOM.DIST
 | 
			
		||||
BINOM.DIST.RANGE
 | 
			
		||||
BINOM.INV
 | 
			
		||||
BITAND
 | 
			
		||||
BITLSHIFT
 | 
			
		||||
BITOR
 | 
			
		||||
BITRSHIFT
 | 
			
		||||
BITXOR
 | 
			
		||||
BYCOL
 | 
			
		||||
BYROW
 | 
			
		||||
CEILING.MATH
 | 
			
		||||
CEILING.PRECISE
 | 
			
		||||
CHISQ.DIST
 | 
			
		||||
CHISQ.DIST.RT
 | 
			
		||||
CHISQ.INV
 | 
			
		||||
CHISQ.INV.RT
 | 
			
		||||
CHISQ.TEST
 | 
			
		||||
COMBINA
 | 
			
		||||
CONFIDENCE.NORM
 | 
			
		||||
CONFIDENCE.T
 | 
			
		||||
COT
 | 
			
		||||
COTH
 | 
			
		||||
COVARIANCE.P
 | 
			
		||||
COVARIANCE.S
 | 
			
		||||
CSC
 | 
			
		||||
CSCH
 | 
			
		||||
DAYS
 | 
			
		||||
DECIMAL
 | 
			
		||||
ERF.PRECISE
 | 
			
		||||
ERFC.PRECISE
 | 
			
		||||
EXPON.DIST
 | 
			
		||||
F.DIST
 | 
			
		||||
F.DIST.RT
 | 
			
		||||
F.INV
 | 
			
		||||
F.INV.RT
 | 
			
		||||
F.TEST
 | 
			
		||||
FIELDVALUE
 | 
			
		||||
FILTERXML
 | 
			
		||||
FLOOR.MATH
 | 
			
		||||
FLOOR.PRECISE
 | 
			
		||||
FORMULATEXT
 | 
			
		||||
GAMMA
 | 
			
		||||
GAMMA.DIST
 | 
			
		||||
GAMMA.INV
 | 
			
		||||
GAMMALN.PRECISE
 | 
			
		||||
GAUSS
 | 
			
		||||
HYPGEOM.DIST
 | 
			
		||||
IFNA
 | 
			
		||||
IMCOSH
 | 
			
		||||
IMCOT
 | 
			
		||||
IMCSC
 | 
			
		||||
IMCSCH
 | 
			
		||||
IMSEC
 | 
			
		||||
IMSECH
 | 
			
		||||
IMSINH
 | 
			
		||||
IMTAN
 | 
			
		||||
ISFORMULA
 | 
			
		||||
ISOMITTED
 | 
			
		||||
ISOWEEKNUM
 | 
			
		||||
LAMBDA
 | 
			
		||||
LET
 | 
			
		||||
LOGNORM.DIST
 | 
			
		||||
LOGNORM.INV
 | 
			
		||||
MAKEARRAY
 | 
			
		||||
MAP
 | 
			
		||||
MODE.MULT
 | 
			
		||||
MODE.SNGL
 | 
			
		||||
MUNIT
 | 
			
		||||
NEGBINOM.DIST
 | 
			
		||||
NORM.DIST
 | 
			
		||||
NORM.INV
 | 
			
		||||
NORM.S.DIST
 | 
			
		||||
NORM.S.INV
 | 
			
		||||
NUMBERVALUE
 | 
			
		||||
PDURATION
 | 
			
		||||
PERCENTILE.EXC
 | 
			
		||||
PERCENTILE.INC
 | 
			
		||||
PERCENTRANK.EXC
 | 
			
		||||
PERCENTRANK.INC
 | 
			
		||||
PERMUTATIONA
 | 
			
		||||
PHI
 | 
			
		||||
POISSON.DIST
 | 
			
		||||
QUARTILE.EXC
 | 
			
		||||
QUARTILE.INC
 | 
			
		||||
QUERYSTRING
 | 
			
		||||
RANDARRAY
 | 
			
		||||
RANK.AVG
 | 
			
		||||
RANK.EQ
 | 
			
		||||
REDUCE
 | 
			
		||||
RRI
 | 
			
		||||
SCAN
 | 
			
		||||
SEC
 | 
			
		||||
SECH
 | 
			
		||||
SEQUENCE
 | 
			
		||||
SHEET
 | 
			
		||||
SHEETS
 | 
			
		||||
SKEW.P
 | 
			
		||||
SORTBY
 | 
			
		||||
STDEV.P
 | 
			
		||||
STDEV.S
 | 
			
		||||
T.DIST
 | 
			
		||||
T.DIST.2T
 | 
			
		||||
T.DIST.RT
 | 
			
		||||
T.INV
 | 
			
		||||
T.INV.2T
 | 
			
		||||
T.TEST
 | 
			
		||||
UNICHAR
 | 
			
		||||
UNICODE
 | 
			
		||||
UNIQUE
 | 
			
		||||
VAR.P
 | 
			
		||||
VAR.S
 | 
			
		||||
WEBSERVICE
 | 
			
		||||
WEIBULL.DIST
 | 
			
		||||
XLOOKUP
 | 
			
		||||
XOR
 | 
			
		||||
Z.TEST
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#### Row and Column Properties
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,14 +10,17 @@
 | 
			
		||||
  * [Parsing Workbooks](README.md#parsing-workbooks)
 | 
			
		||||
  * [Processing JSON and JS Data](README.md#processing-json-and-js-data)
 | 
			
		||||
  * [Processing HTML Tables](README.md#processing-html-tables)
 | 
			
		||||
- [Working with the Workbook](README.md#working-with-the-workbook)
 | 
			
		||||
  * [Parsing and Writing Examples](README.md#parsing-and-writing-examples)
 | 
			
		||||
- [Processing Data](README.md#processing-data)
 | 
			
		||||
  * [Modifying Workbook Structure](README.md#modifying-workbook-structure)
 | 
			
		||||
  * [Modifying Cell Values](README.md#modifying-cell-values)
 | 
			
		||||
  * [Modifying Other Worksheet / Workbook / Cell Properties](README.md#modifying-other-worksheet--workbook--cell-properties)
 | 
			
		||||
- [Packaging and Releasing Data](README.md#packaging-and-releasing-data)
 | 
			
		||||
  * [Writing Workbooks](README.md#writing-workbooks)
 | 
			
		||||
  * [Writing Examples](README.md#writing-examples)
 | 
			
		||||
  * [Streaming Write](README.md#streaming-write)
 | 
			
		||||
  * [Generating JSON and JS Data](README.md#generating-json-and-js-data)
 | 
			
		||||
  * [Generating HTML Tables](README.md#generating-html-tables)
 | 
			
		||||
  * [Generating Single-Worksheet Snapshots](README.md#generating-single-worksheet-snapshots)
 | 
			
		||||
- [Interface](README.md#interface)
 | 
			
		||||
  * [Parsing functions](README.md#parsing-functions)
 | 
			
		||||
  * [Writing functions](README.md#writing-functions)
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,7 @@ bits/47_styxml.js
 | 
			
		||||
bits/48_stybin.js
 | 
			
		||||
bits/49_theme.js
 | 
			
		||||
bits/50_styxls.js
 | 
			
		||||
bits/51_xlmeta.js
 | 
			
		||||
bits/52_calcchain.js
 | 
			
		||||
bits/53_externlink.js
 | 
			
		||||
bits/54_drawing.js
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										151
									
								
								modules/51_xlmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										151
									
								
								modules/51_xlmeta.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,151 @@
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
function parse_xlmeta_xml(data, name, opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  if (!data)
 | 
			
		||||
    return out;
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  data.replace(tagregex, function(x, idx) {
 | 
			
		||||
    var y = parsexmltag(x);
 | 
			
		||||
    switch (strip_ns(y[0])) {
 | 
			
		||||
      case "<?xml":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadata":
 | 
			
		||||
      case "</metadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataTypes":
 | 
			
		||||
      case "</metadataTypes>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataType":
 | 
			
		||||
        out.Types.push({ name: y.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case "<futureMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</futureMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<rc":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</rc>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<cellMetadata":
 | 
			
		||||
      case "</cellMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<valueMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</valueMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<extLst":
 | 
			
		||||
      case "<extLst>":
 | 
			
		||||
      case "</extLst>":
 | 
			
		||||
      case "<extLst/>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<ext":
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case "</ext>":
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (!pass && opts.WTF)
 | 
			
		||||
          throw new Error("unrecognized " + y[0] + " in metadata");
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_xml() {
 | 
			
		||||
  var o = [XML_HEADER];
 | 
			
		||||
  o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>');
 | 
			
		||||
  return o.join("");
 | 
			
		||||
}
 | 
			
		||||
function parse_BrtMdtinfo(data, length) {
 | 
			
		||||
  return {
 | 
			
		||||
    flags: data.read_shift(4),
 | 
			
		||||
    version: data.read_shift(4),
 | 
			
		||||
    name: parse_XLWideString(data, length - 8)
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdtinfo(data) {
 | 
			
		||||
  var o = new_buf(12 + 2 * data.name.length);
 | 
			
		||||
  o.write_shift(4, data.flags);
 | 
			
		||||
  o.write_shift(4, data.version);
 | 
			
		||||
  write_XLWideString(data.name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdb(mdb) {
 | 
			
		||||
  var o = new_buf(4 + 8 * mdb.length);
 | 
			
		||||
  o.write_shift(4, mdb.length);
 | 
			
		||||
  for (var i = 0; i < mdb.length; ++i) {
 | 
			
		||||
    o.write_shift(4, mdb[i][0]);
 | 
			
		||||
    o.write_shift(4, mdb[i][1]);
 | 
			
		||||
  }
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsfmd(cnt, name) {
 | 
			
		||||
  var o = new_buf(8 + 2 * name.length);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  write_XLWideString(name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsmdb(cnt, cm) {
 | 
			
		||||
  var o = new_buf(8);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  o.write_shift(4, cm ? 1 : 0);
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function parse_xlmeta_bin(data, name, _opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  var opts = _opts || {};
 | 
			
		||||
  var state = [];
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  recordhopper(data, function(val, R_n, RT) {
 | 
			
		||||
    switch (RT) {
 | 
			
		||||
      case 335:
 | 
			
		||||
        out.Types.push({ name: val.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case 51:
 | 
			
		||||
        break;
 | 
			
		||||
      case 35:
 | 
			
		||||
        state.push(R_n);
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case 36:
 | 
			
		||||
        state.pop();
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if ((R_n || "").indexOf("Begin") > 0) {
 | 
			
		||||
        } else if ((R_n || "").indexOf("End") > 0) {
 | 
			
		||||
        } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
 | 
			
		||||
          throw new Error("Unexpected record " + RT + " " + R_n);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_bin() {
 | 
			
		||||
  var ba = buf_array();
 | 
			
		||||
  write_record(ba, "BrtBeginMetadata");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
 | 
			
		||||
  write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
 | 
			
		||||
    name: "XLDAPR",
 | 
			
		||||
    version: 12e4,
 | 
			
		||||
    flags: 3496657072
 | 
			
		||||
  }));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdtinfo");
 | 
			
		||||
  write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
 | 
			
		||||
  write_record(ba, "BrtBeginFmd");
 | 
			
		||||
  write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
 | 
			
		||||
  write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
 | 
			
		||||
  write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
 | 
			
		||||
  write_record(ba, "BrtFRTEnd");
 | 
			
		||||
  write_record(ba, "BrtEndFmd");
 | 
			
		||||
  write_record(ba, "BrtEndEsfmd");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
 | 
			
		||||
  write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdb");
 | 
			
		||||
  write_record(ba, "BrtEndMetadata");
 | 
			
		||||
  return ba.end();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										88
									
								
								modules/51_xlsbmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										88
									
								
								modules/51_xlsbmeta.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,88 @@
 | 
			
		||||
function parse_BrtMdtinfo(data, length) {
 | 
			
		||||
  return {
 | 
			
		||||
    flags: data.read_shift(4),
 | 
			
		||||
    version: data.read_shift(4),
 | 
			
		||||
    name: parse_XLWideString(data, length - 8)
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdtinfo(data) {
 | 
			
		||||
  var o = new_buf(12 + 2 * data.name.length);
 | 
			
		||||
  o.write_shift(4, data.flags);
 | 
			
		||||
  o.write_shift(4, data.version);
 | 
			
		||||
  write_XLWideString(data.name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdb(mdb) {
 | 
			
		||||
  var o = new_buf(4 + 8 * mdb.length);
 | 
			
		||||
  o.write_shift(4, mdb.length);
 | 
			
		||||
  for (var i = 0; i < mdb.length; ++i) {
 | 
			
		||||
    o.write_shift(4, mdb[i][0]);
 | 
			
		||||
    o.write_shift(4, mdb[i][1]);
 | 
			
		||||
  }
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsfmd(cnt, name) {
 | 
			
		||||
  var o = new_buf(8 + 2 * name.length);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  write_XLWideString(name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsmdb(cnt, cm) {
 | 
			
		||||
  var o = new_buf(8);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  o.write_shift(4, cm ? 1 : 0);
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function parse_xlmeta_bin(data, name, _opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  var opts = _opts || {};
 | 
			
		||||
  var state = [];
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  recordhopper(data, function(val, R_n, RT) {
 | 
			
		||||
    switch (RT) {
 | 
			
		||||
      case 335:
 | 
			
		||||
        out.Types.push({ name: val.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case 51:
 | 
			
		||||
        break;
 | 
			
		||||
      case 35:
 | 
			
		||||
        state.push(R_n);
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case 36:
 | 
			
		||||
        state.pop();
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if ((R_n || "").indexOf("Begin") > 0) {
 | 
			
		||||
        } else if ((R_n || "").indexOf("End") > 0) {
 | 
			
		||||
        } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
 | 
			
		||||
          throw new Error("Unexpected record " + RT + " " + R_n);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_bin() {
 | 
			
		||||
  var ba = buf_array();
 | 
			
		||||
  write_record(ba, "BrtBeginMetadata");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
 | 
			
		||||
  write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
 | 
			
		||||
    name: "XLDAPR",
 | 
			
		||||
    version: 12e4,
 | 
			
		||||
    flags: 3496657072
 | 
			
		||||
  }));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdtinfo");
 | 
			
		||||
  write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
 | 
			
		||||
  write_record(ba, "BrtBeginFmd");
 | 
			
		||||
  write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
 | 
			
		||||
  write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
 | 
			
		||||
  write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
 | 
			
		||||
  write_record(ba, "BrtFRTEnd");
 | 
			
		||||
  write_record(ba, "BrtEndFmd");
 | 
			
		||||
  write_record(ba, "BrtEndEsfmd");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
 | 
			
		||||
  write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdb");
 | 
			
		||||
  write_record(ba, "BrtEndMetadata");
 | 
			
		||||
  return ba.end();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										120
									
								
								modules/51_xlsbmeta.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										120
									
								
								modules/51_xlsbmeta.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
			
		||||
/// <reference path="src/types.ts"/>
 | 
			
		||||
 | 
			
		||||
/* [MS-XLSB] 2.4.698 BrtMdtinfo */
 | 
			
		||||
interface BrtMdtinfo {
 | 
			
		||||
	flags: number;
 | 
			
		||||
	version: number;
 | 
			
		||||
	name: string;
 | 
			
		||||
}
 | 
			
		||||
function parse_BrtMdtinfo(data: ReadableData, length: number): BrtMdtinfo {
 | 
			
		||||
	return {
 | 
			
		||||
		flags: data.read_shift(4),
 | 
			
		||||
		version: data.read_shift(4),
 | 
			
		||||
		name: parse_XLWideString(data, length - 8)
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdtinfo(data: BrtMdtinfo): RawData {
 | 
			
		||||
	var o = new_buf(12 + 2 * data.name.length);
 | 
			
		||||
	o.write_shift(4, data.flags);
 | 
			
		||||
	o.write_shift(4, data.version);
 | 
			
		||||
	write_XLWideString(data.name, o);
 | 
			
		||||
	return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* [MS-XLSB] 2.4.697 BrtMdb */
 | 
			
		||||
type Mdir = [number, number]; // "t", "v" in XLSX parlance
 | 
			
		||||
type BrtMdb = Mdir[];
 | 
			
		||||
function write_BrtMdb(mdb: BrtMdb): RawData {
 | 
			
		||||
	var o = new_buf(4 + 8 * mdb.length);
 | 
			
		||||
	o.write_shift(4, mdb.length);
 | 
			
		||||
	for(var i = 0; i < mdb.length; ++i) {
 | 
			
		||||
		o.write_shift(4, mdb[i][0]);
 | 
			
		||||
		o.write_shift(4, mdb[i][1]);
 | 
			
		||||
	}
 | 
			
		||||
	return o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* [MS-XLSB] 2.4.72 BrtBeginEsfmd */
 | 
			
		||||
function write_BrtBeginEsfmd(cnt: number, name: string): RawData {
 | 
			
		||||
	var o = new_buf(8 + 2 * name.length);
 | 
			
		||||
	o.write_shift(4, cnt);
 | 
			
		||||
	write_XLWideString(name, o);
 | 
			
		||||
	return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* [MS-XLSB] 2.4.73 BrtBeginEsmdb */
 | 
			
		||||
function write_BrtBeginEsmdb(cnt: number, cm: boolean): RawData {
 | 
			
		||||
	var o = new_buf(8);
 | 
			
		||||
	o.write_shift(4, cnt);
 | 
			
		||||
	o.write_shift(4, cm ? 1 : 0);
 | 
			
		||||
	return o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* [MS-XLSB] 2.1.7.34 Metadata */
 | 
			
		||||
function parse_xlmeta_bin(data, name: string, _opts?: ParseXLMetaOptions): XLMeta {
 | 
			
		||||
	var out: XLMeta = { Types: [] };
 | 
			
		||||
	var opts = _opts || {};
 | 
			
		||||
	var state: string[] = [];
 | 
			
		||||
	var pass = false;
 | 
			
		||||
 | 
			
		||||
	recordhopper(data, (val, R_n, RT) => {
 | 
			
		||||
		switch(RT) {
 | 
			
		||||
			// case 0x014C: /* 'BrtBeginMetadata' */
 | 
			
		||||
			// case 0x014D: /* 'BrtEndMetadata' */
 | 
			
		||||
			// case 0x014E: /* 'BrtBeginEsmdtinfo' */
 | 
			
		||||
			// case 0x0150: /* 'BrtEndEsmdtinfo' */
 | 
			
		||||
			// case 0x0151: /* 'BrtBeginEsmdb' */
 | 
			
		||||
			// case 0x0152: /* 'BrtEndEsmdb' */
 | 
			
		||||
			// case 0x0153: /* 'BrtBeginEsfmd' */
 | 
			
		||||
			// case 0x0154: /* 'BrtEndEsfmd' */
 | 
			
		||||
			// case 0x0034: /* 'BrtBeginFmd' */
 | 
			
		||||
			// case 0x0035: /* 'BrtEndFmd' */
 | 
			
		||||
			// case 0x1000: /* 'BrtBeginDynamicArrayPr' */
 | 
			
		||||
			// case 0x1001: /* 'BrtEndDynamicArrayPr' */
 | 
			
		||||
			// case 0x138A: /* 'BrtBeginRichValueBlock' */
 | 
			
		||||
			// case 0x138B: /* 'BrtEndRichValueBlock' */
 | 
			
		||||
 | 
			
		||||
			case 0x014F: /* 'BrtMdtinfo' */
 | 
			
		||||
				out.Types.push({name: (val as BrtMdtinfo).name});
 | 
			
		||||
				break;
 | 
			
		||||
			case 0x0033: /* 'BrtMdb' */
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x0023: /* 'BrtFRTBegin' */
 | 
			
		||||
				state.push(R_n); pass = true; break;
 | 
			
		||||
			case 0x0024: /* 'BrtFRTEnd' */
 | 
			
		||||
				state.pop(); pass = false; break;
 | 
			
		||||
			default:
 | 
			
		||||
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
 | 
			
		||||
				else if((R_n||"").indexOf("End") > 0){/* empty */}
 | 
			
		||||
				else if(!pass || (opts.WTF && state[state.length-1] != "BrtFRTBegin")) throw new Error("Unexpected record " + RT + " " + R_n);
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_bin() {
 | 
			
		||||
	var ba = buf_array();
 | 
			
		||||
	write_record(ba, "BrtBeginMetadata");
 | 
			
		||||
	write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
 | 
			
		||||
	write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
 | 
			
		||||
		name: "XLDAPR",
 | 
			
		||||
		version: 120000,
 | 
			
		||||
		flags: 0xD06AC0B0
 | 
			
		||||
	}));
 | 
			
		||||
	write_record(ba, "BrtEndEsmdtinfo");
 | 
			
		||||
	/* [ESSTR] [ESMDX] */
 | 
			
		||||
	write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
 | 
			
		||||
	write_record(ba, "BrtBeginFmd");
 | 
			
		||||
	write_record(ba, "BrtFRTBegin", write_UInt32LE(0x0202));
 | 
			
		||||
	write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
 | 
			
		||||
	write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
 | 
			
		||||
	write_record(ba, "BrtFRTEnd");
 | 
			
		||||
	write_record(ba, "BrtEndFmd");
 | 
			
		||||
	write_record(ba, "BrtEndEsfmd");
 | 
			
		||||
	write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
 | 
			
		||||
	write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
 | 
			
		||||
	write_record(ba, "BrtEndEsmdb");
 | 
			
		||||
	/* *FRT */
 | 
			
		||||
	write_record(ba, "BrtEndMetadata");
 | 
			
		||||
	return ba.end();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								modules/51_xlsxmeta.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										63
									
								
								modules/51_xlsxmeta.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,63 @@
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
function parse_xlmeta_xml(data, name, opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  if (!data)
 | 
			
		||||
    return out;
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  data.replace(tagregex, function(x, idx) {
 | 
			
		||||
    var y = parsexmltag(x);
 | 
			
		||||
    switch (strip_ns(y[0])) {
 | 
			
		||||
      case "<?xml":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadata":
 | 
			
		||||
      case "</metadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataTypes":
 | 
			
		||||
      case "</metadataTypes>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataType":
 | 
			
		||||
        out.Types.push({ name: y.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case "<futureMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</futureMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<rc":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</rc>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<cellMetadata":
 | 
			
		||||
      case "</cellMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<valueMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</valueMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<extLst":
 | 
			
		||||
      case "<extLst>":
 | 
			
		||||
      case "</extLst>":
 | 
			
		||||
      case "<extLst/>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<ext":
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case "</ext>":
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (!pass && opts.WTF)
 | 
			
		||||
          throw new Error("unrecognized " + y[0] + " in metadata");
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_xml() {
 | 
			
		||||
  var o = [XML_HEADER];
 | 
			
		||||
  o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>');
 | 
			
		||||
  return o.join("");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										85
									
								
								modules/51_xlsxmeta.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										85
									
								
								modules/51_xlsxmeta.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,85 @@
 | 
			
		||||
/// <reference path="src/types.ts"/>
 | 
			
		||||
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
 | 
			
		||||
/* 12.3.10 Metadata Part */
 | 
			
		||||
function parse_xlmeta_xml(data: string, name: string, opts?: ParseXLMetaOptions): XLMeta {
 | 
			
		||||
	var out: XLMeta = { Types: [] };
 | 
			
		||||
	if(!data) return out;
 | 
			
		||||
	var pass = false;
 | 
			
		||||
 | 
			
		||||
	data.replace(tagregex, (x: string, idx: number) => {
 | 
			
		||||
		var y: any = parsexmltag(x);
 | 
			
		||||
		switch(strip_ns(y[0])) {
 | 
			
		||||
			case '<?xml': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.9.8 */
 | 
			
		||||
			case '<metadata': case '</metadata>': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.9.11 */
 | 
			
		||||
			case '<metadataTypes': case '</metadataTypes>': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.9.10 */
 | 
			
		||||
			case '<metadataType':
 | 
			
		||||
				out.Types.push({ name: y.name });
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			/* 18.9.4 */
 | 
			
		||||
			case '<futureMetadata': break;
 | 
			
		||||
			case '</futureMetadata>': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.9.1 */
 | 
			
		||||
			case '<bk>': break;
 | 
			
		||||
			case '</bk>': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.9.15 */
 | 
			
		||||
			case '<rc': break;
 | 
			
		||||
			case '</rc>': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.9.3 */
 | 
			
		||||
			case '<cellMetadata':
 | 
			
		||||
			case '</cellMetadata>': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.9.17 */
 | 
			
		||||
			case '<valueMetadata': break;
 | 
			
		||||
			case '</valueMetadata>': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.2.10 extLst CT_ExtensionList ? */
 | 
			
		||||
			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
 | 
			
		||||
 | 
			
		||||
			/* 18.2.7  ext CT_Extension + */
 | 
			
		||||
			case '<ext': pass=true; break; //TODO: check with versions of excel
 | 
			
		||||
			case '</ext>': pass=false; break;
 | 
			
		||||
 | 
			
		||||
			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in metadata');
 | 
			
		||||
		}
 | 
			
		||||
		return x;
 | 
			
		||||
	});
 | 
			
		||||
	return out;
 | 
			
		||||
}
 | 
			
		||||
/* TODO: coordinate with cell writing, pass flags */
 | 
			
		||||
function write_xlmeta_xml(): string {
 | 
			
		||||
	var o = [XML_HEADER];
 | 
			
		||||
	o.push(`\
 | 
			
		||||
<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">
 | 
			
		||||
  <metadataTypes count="1">
 | 
			
		||||
    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>
 | 
			
		||||
  </metadataTypes>
 | 
			
		||||
  <futureMetadata name="XLDAPR" count="1">
 | 
			
		||||
    <bk>
 | 
			
		||||
      <extLst>
 | 
			
		||||
        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">
 | 
			
		||||
          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>
 | 
			
		||||
        </ext>
 | 
			
		||||
      </extLst>
 | 
			
		||||
    </bk>
 | 
			
		||||
  </futureMetadata>
 | 
			
		||||
  <cellMetadata count="1">
 | 
			
		||||
    <bk>
 | 
			
		||||
      <rc t="1" v="0"/>
 | 
			
		||||
    </bk>
 | 
			
		||||
  </cellMetadata>
 | 
			
		||||
</metadata>`);
 | 
			
		||||
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
@ -2,10 +2,13 @@ LIBFILES=$(wildcard src/*.ts)
 | 
			
		||||
TSFILES=$(wildcard *.ts)
 | 
			
		||||
ENTRIES=$(subst .ts,.js,$(TSFILES))
 | 
			
		||||
 | 
			
		||||
BAREJS=04_base64.js 59_vba.js 64_ftab.js
 | 
			
		||||
BAREJS=04_base64.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js
 | 
			
		||||
 | 
			
		||||
.PHONY: all
 | 
			
		||||
all: $(ENTRIES)
 | 
			
		||||
all: $(ENTRIES) 51_xlmeta.js
 | 
			
		||||
 | 
			
		||||
51_xlmeta.js: 51_xlsxmeta.js 51_xlsbmeta.js
 | 
			
		||||
	cat $^ > $@
 | 
			
		||||
 | 
			
		||||
$(BAREJS): %.js: %.ts $(LIBFILES)
 | 
			
		||||
	npx esbuild $< --outfile=$@ --platform=browser --target=es5
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								modules/src/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										44
									
								
								modules/src/types.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
declare type RawData = Uint8Array | number[];
 | 
			
		||||
declare function recordhopper(data: RawData, cb:(val: any, R_n: string, RT: number)=>void): void;
 | 
			
		||||
declare interface ReadableData {
 | 
			
		||||
	l: number;
 | 
			
		||||
	read_shift(t: 4): number;
 | 
			
		||||
	read_shift(t: any): any;
 | 
			
		||||
}
 | 
			
		||||
declare type ParseFunc<T> = (data: ReadableData, length: number) => T;
 | 
			
		||||
declare var parse_XLWideString: ParseFunc<string>;
 | 
			
		||||
 | 
			
		||||
declare interface WritableData {
 | 
			
		||||
	l: number;
 | 
			
		||||
	write_shift(t: 4, val: number): void;
 | 
			
		||||
	write_shift(t: number, val: string|number, f?: string): any;
 | 
			
		||||
}
 | 
			
		||||
declare type WritableRawData = WritableData & RawData;
 | 
			
		||||
interface BufArray {
 | 
			
		||||
	end(): RawData;
 | 
			
		||||
	next(sz: number): WritableData;
 | 
			
		||||
	push(buf: RawData): void;
 | 
			
		||||
}
 | 
			
		||||
declare function buf_array(): BufArray;
 | 
			
		||||
declare function write_record(ba: BufArray, type: string, payload?: RawData, length?: number): void;
 | 
			
		||||
declare function new_buf(sz: number): RawData & WritableData & ReadableData;
 | 
			
		||||
 | 
			
		||||
declare var tagregex: RegExp;
 | 
			
		||||
declare var XML_HEADER: string;
 | 
			
		||||
declare var RELS: any;
 | 
			
		||||
declare function parsexmltag(tag: string, skip_root?: boolean, skip_LC?: boolean): object;
 | 
			
		||||
declare function strip_ns(x: string): string;
 | 
			
		||||
declare function write_UInt32LE(x: number, o?: WritableData): RawData;
 | 
			
		||||
declare function write_XLWideString(data: string, o?: WritableData): RawData;
 | 
			
		||||
declare function writeuint16(x: number): RawData;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
interface ParseXLMetaOptions {
 | 
			
		||||
	WTF?: number|boolean;
 | 
			
		||||
}
 | 
			
		||||
interface XLMDT {
 | 
			
		||||
	name: string;
 | 
			
		||||
}
 | 
			
		||||
interface XLMeta {
 | 
			
		||||
	Types: XLMDT[];
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "xlsx",
 | 
			
		||||
	"version": "0.18.2",
 | 
			
		||||
	"version": "0.18.3",
 | 
			
		||||
	"author": "sheetjs",
 | 
			
		||||
	"description": "SheetJS Spreadsheet data parser and writer",
 | 
			
		||||
	"keywords": [
 | 
			
		||||
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
Subproject commit c8fe8a48a8cfc3c480b02f0a6df75cc2aff1932d
 | 
			
		||||
Subproject commit 8203afea252b2817ec0a67e18f3b7c9503d50b97
 | 
			
		||||
							
								
								
									
										2
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							@ -833,7 +833,7 @@ export interface XLSX$Utils {
 | 
			
		||||
    cell_add_comment(cell: CellObject, text: string, author?: string): void;
 | 
			
		||||
 | 
			
		||||
    /** Assign an Array Formula to a range */
 | 
			
		||||
    sheet_set_array_formula(ws: WorkSheet, range: Range|string, formula: string): WorkSheet;
 | 
			
		||||
    sheet_set_array_formula(ws: WorkSheet, range: Range|string, formula: string, dynamic?: boolean): WorkSheet;
 | 
			
		||||
 | 
			
		||||
    /** Add an array of arrays of JS data to a worksheet */
 | 
			
		||||
    sheet_add_aoa<T>(ws: WorkSheet, data: T[][], opts?: SheetAOAOpts): WorkSheet;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										311
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										311
									
								
								xlsx.flow.js
									
									
									
									
									
								
							@ -4,7 +4,7 @@
 | 
			
		||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
 | 
			
		||||
var XLSX = {};
 | 
			
		||||
function make_xlsx_lib(XLSX){
 | 
			
		||||
XLSX.version = '0.18.2';
 | 
			
		||||
XLSX.version = '0.18.3';
 | 
			
		||||
var current_codepage = 1200, current_ansi = 1252;
 | 
			
		||||
/*:: declare var cptable:any; */
 | 
			
		||||
/*global cptable:true, window */
 | 
			
		||||
@ -3189,7 +3189,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
 | 
			
		||||
	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
 | 
			
		||||
	if(typeof Deno !== 'undefined') {
 | 
			
		||||
		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
 | 
			
		||||
		if(enc) switch(enc) {
 | 
			
		||||
		if(enc && typeof payload == "string") switch(enc) {
 | 
			
		||||
			case "utf8": payload = new TextEncoder(enc).encode(payload); break;
 | 
			
		||||
			case "binary": payload = s2ab(payload); break;
 | 
			
		||||
			/* TODO: binary equivalent */
 | 
			
		||||
@ -4144,44 +4144,6 @@ function encode_range_xls(r, opts)/*:string*/ {
 | 
			
		||||
	}
 | 
			
		||||
	return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
 | 
			
		||||
}
 | 
			
		||||
var OFFCRYPTO = {};
 | 
			
		||||
 | 
			
		||||
var make_offcrypto = function(O, _crypto) {
 | 
			
		||||
	var crypto;
 | 
			
		||||
	if(typeof _crypto !== 'undefined') crypto = _crypto;
 | 
			
		||||
	else if(typeof require !== 'undefined') {
 | 
			
		||||
		try { crypto = require('crypto'); }
 | 
			
		||||
		catch(e) { crypto = null; }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	O.rc4 = function(key, data) {
 | 
			
		||||
		var S = new Array(256);
 | 
			
		||||
		var c = 0, i = 0, j = 0, t = 0;
 | 
			
		||||
		for(i = 0; i != 256; ++i) S[i] = i;
 | 
			
		||||
		for(i = 0; i != 256; ++i) {
 | 
			
		||||
			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
 | 
			
		||||
			t = S[i]; S[i] = S[j]; S[j] = t;
 | 
			
		||||
		}
 | 
			
		||||
		// $FlowIgnore
 | 
			
		||||
		i = j = 0; var out = new_raw_buf(data.length);
 | 
			
		||||
		for(c = 0; c != data.length; ++c) {
 | 
			
		||||
			i = (i + 1)&255;
 | 
			
		||||
			j = (j + S[i])%256;
 | 
			
		||||
			t = S[i]; S[i] = S[j]; S[j] = t;
 | 
			
		||||
			out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
 | 
			
		||||
		}
 | 
			
		||||
		return out;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	O.md5 = function(hex) {
 | 
			
		||||
		if(!crypto) throw new Error("Unsupported crypto");
 | 
			
		||||
		return crypto.createHash('md5').update(hex).digest('hex');
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
/*:: declare var crypto:any; */
 | 
			
		||||
/*global crypto:true */
 | 
			
		||||
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
 | 
			
		||||
 | 
			
		||||
function decode_row(rowstr/*:string*/)/*:number*/ { return parseInt(unfix_row(rowstr),10) - 1; }
 | 
			
		||||
function encode_row(row/*:number*/)/*:string*/ { return "" + (row + 1); }
 | 
			
		||||
function fix_row(cstr/*:string*/)/*:string*/ { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
 | 
			
		||||
@ -4351,6 +4313,9 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
 | 
			
		||||
}
 | 
			
		||||
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); }
 | 
			
		||||
 | 
			
		||||
function parse_Int32LE(data) {
 | 
			
		||||
	return data.read_shift(4, 'i');
 | 
			
		||||
}
 | 
			
		||||
function write_UInt32LE(x/*:number*/, o) {
 | 
			
		||||
	if (!o) o = new_buf(4);
 | 
			
		||||
	o.write_shift(4, x);
 | 
			
		||||
@ -5016,8 +4981,8 @@ var ct2type/*{[string]:string}*/ = ({
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
 | 
			
		||||
 | 
			
		||||
	/* Metadata */
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "TODO",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "metadata",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
 | 
			
		||||
 | 
			
		||||
	/* PivotCache */
 | 
			
		||||
	"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
 | 
			
		||||
@ -5134,6 +5099,10 @@ var CT_LIST = (function(){
 | 
			
		||||
			xlsx: "application/vnd.ms-excel.macrosheet+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.macrosheet"
 | 
			
		||||
		},
 | 
			
		||||
		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.sheetMetadata"
 | 
			
		||||
		},
 | 
			
		||||
		styles: { /* Styles */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.styles"
 | 
			
		||||
@ -5153,7 +5122,7 @@ function new_ct()/*:any*/ {
 | 
			
		||||
		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
 | 
			
		||||
		rels:[], strs:[], comments:[], links:[],
 | 
			
		||||
		coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [], metadata: [],
 | 
			
		||||
		TODO:[], xmlns: "" }/*:any*/);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5252,6 +5221,7 @@ function write_ct(ct, opts)/*:string*/ {
 | 
			
		||||
	f3('vba');
 | 
			
		||||
	f3('comments');
 | 
			
		||||
	f3('drawings');
 | 
			
		||||
	f2('metadata');
 | 
			
		||||
	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
@ -5318,7 +5288,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
 | 
			
		||||
function add_rels(rels, rId/*:number*/, f, type, relobj, targetmode/*:?string*/)/*:number*/ {
 | 
			
		||||
	if(!relobj) relobj = {};
 | 
			
		||||
	if(!rels['!id']) rels['!id'] = {};
 | 
			
		||||
	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
 | 
			
		||||
	if(!rels['!idx']) rels['!idx'] = 1;
 | 
			
		||||
	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */}
 | 
			
		||||
	rels['!idx'] = rId + 1;
 | 
			
		||||
	relobj.Id = 'rId' + rId;
 | 
			
		||||
	relobj.Type = type;
 | 
			
		||||
	relobj.Target = f;
 | 
			
		||||
@ -11310,6 +11282,157 @@ function update_xfext(xf, xfext) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
function parse_xlmeta_xml(data, name, opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  if (!data)
 | 
			
		||||
    return out;
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  data.replace(tagregex, function(x, idx) {
 | 
			
		||||
    var y = parsexmltag(x);
 | 
			
		||||
    switch (strip_ns(y[0])) {
 | 
			
		||||
      case "<?xml":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadata":
 | 
			
		||||
      case "</metadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataTypes":
 | 
			
		||||
      case "</metadataTypes>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataType":
 | 
			
		||||
        out.Types.push({ name: y.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case "<futureMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</futureMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<rc":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</rc>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<cellMetadata":
 | 
			
		||||
      case "</cellMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<valueMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</valueMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<extLst":
 | 
			
		||||
      case "<extLst>":
 | 
			
		||||
      case "</extLst>":
 | 
			
		||||
      case "<extLst/>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<ext":
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case "</ext>":
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (!pass && opts.WTF)
 | 
			
		||||
          throw new Error("unrecognized " + y[0] + " in metadata");
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_xml() {
 | 
			
		||||
  var o = [XML_HEADER];
 | 
			
		||||
  o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>');
 | 
			
		||||
  return o.join("");
 | 
			
		||||
}
 | 
			
		||||
function parse_BrtMdtinfo(data, length) {
 | 
			
		||||
  return {
 | 
			
		||||
    flags: data.read_shift(4),
 | 
			
		||||
    version: data.read_shift(4),
 | 
			
		||||
    name: parse_XLWideString(data, length - 8)
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdtinfo(data) {
 | 
			
		||||
  var o = new_buf(12 + 2 * data.name.length);
 | 
			
		||||
  o.write_shift(4, data.flags);
 | 
			
		||||
  o.write_shift(4, data.version);
 | 
			
		||||
  write_XLWideString(data.name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdb(mdb) {
 | 
			
		||||
  var o = new_buf(4 + 8 * mdb.length);
 | 
			
		||||
  o.write_shift(4, mdb.length);
 | 
			
		||||
  for (var i = 0; i < mdb.length; ++i) {
 | 
			
		||||
    o.write_shift(4, mdb[i][0]);
 | 
			
		||||
    o.write_shift(4, mdb[i][1]);
 | 
			
		||||
  }
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsfmd(cnt, name) {
 | 
			
		||||
  var o = new_buf(8 + 2 * name.length);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  write_XLWideString(name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsmdb(cnt, cm) {
 | 
			
		||||
  var o = new_buf(8);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  o.write_shift(4, cm ? 1 : 0);
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function parse_xlmeta_bin(data, name, _opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  var opts = _opts || {};
 | 
			
		||||
  var state = [];
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  recordhopper(data, function(val, R_n, RT) {
 | 
			
		||||
    switch (RT) {
 | 
			
		||||
      case 335:
 | 
			
		||||
        out.Types.push({ name: val.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case 51:
 | 
			
		||||
        break;
 | 
			
		||||
      case 35:
 | 
			
		||||
        state.push(R_n);
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case 36:
 | 
			
		||||
        state.pop();
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if ((R_n || "").indexOf("Begin") > 0) {
 | 
			
		||||
        } else if ((R_n || "").indexOf("End") > 0) {
 | 
			
		||||
        } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
 | 
			
		||||
          throw new Error("Unexpected record " + RT + " " + R_n);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_bin() {
 | 
			
		||||
  var ba = buf_array();
 | 
			
		||||
  write_record(ba, "BrtBeginMetadata");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
 | 
			
		||||
  write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
 | 
			
		||||
    name: "XLDAPR",
 | 
			
		||||
    version: 12e4,
 | 
			
		||||
    flags: 3496657072
 | 
			
		||||
  }));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdtinfo");
 | 
			
		||||
  write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
 | 
			
		||||
  write_record(ba, "BrtBeginFmd");
 | 
			
		||||
  write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
 | 
			
		||||
  write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
 | 
			
		||||
  write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
 | 
			
		||||
  write_record(ba, "BrtFRTEnd");
 | 
			
		||||
  write_record(ba, "BrtEndFmd");
 | 
			
		||||
  write_record(ba, "BrtEndEsfmd");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
 | 
			
		||||
  write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdb");
 | 
			
		||||
  write_record(ba, "BrtEndMetadata");
 | 
			
		||||
  return ba.end();
 | 
			
		||||
}
 | 
			
		||||
/* 18.6 Calculation Chain */
 | 
			
		||||
function parse_cc_xml(data/*::, name, opts*/)/*:Array<any>*/ {
 | 
			
		||||
	var d = [];
 | 
			
		||||
@ -12636,7 +12759,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
 | 
			
		||||
				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
 | 
			
		||||
				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
 | 
			
		||||
				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
 | 
			
		||||
				stack.push(name);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
@ -14534,6 +14657,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
 | 
			
		||||
	}
 | 
			
		||||
	if(cell.l) ws['!links'].push([ref, cell.l]);
 | 
			
		||||
	if(cell.c) ws['!comments'].push([ref, cell.c]);
 | 
			
		||||
	if(cell.D) o.cm = 1;
 | 
			
		||||
	return writextag('c', v, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14710,6 +14834,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
 | 
			
		||||
			}
 | 
			
		||||
			safe_format(p, fmtid, fillid, opts, themes, styles);
 | 
			
		||||
			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
 | 
			
		||||
			if(tag.cm && opts.xlmeta) {
 | 
			
		||||
				var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
 | 
			
		||||
				if(cm && cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
			}
 | 
			
		||||
			if(dense) {
 | 
			
		||||
				var _r = decode_cell(tag.r);
 | 
			
		||||
				if(!s[_r.r]) s[_r.r] = [];
 | 
			
		||||
@ -15424,6 +15552,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
 | 
			
		||||
	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
 | 
			
		||||
 | 
			
		||||
	var cm, vm;
 | 
			
		||||
 | 
			
		||||
	recordhopper(data, function ws_parse(val, R_n, RT) {
 | 
			
		||||
		if(end) return;
 | 
			
		||||
		switch(RT) {
 | 
			
		||||
@ -15481,6 +15611,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
					}
 | 
			
		||||
					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;
 | 
			
		||||
@ -15488,12 +15619,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
				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); }
 | 
			
		||||
				}
 | 
			
		||||
				if(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x0001: /* 'BrtCellBlank' */
 | 
			
		||||
			case 0x000C: /* 'BrtShortBlank' */
 | 
			
		||||
				if(!opts.sheetStubs || pass) break;
 | 
			
		||||
				p = ({t:'z',v:undefined}/*:any*/);
 | 
			
		||||
				p = ({t:'z',v:void 0}/*:any*/);
 | 
			
		||||
				C = val[0].c == -1 ? C + 1 : val[0].c;
 | 
			
		||||
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
 | 
			
		||||
				else s[encode_col(C) + rr] = p;
 | 
			
		||||
@ -15501,11 +15637,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
				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(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x00B0: /* 'BrtMergeCell' */
 | 
			
		||||
				merges.push(val); break;
 | 
			
		||||
 | 
			
		||||
			case 0x0031: { /* 'BrtCellMeta' */
 | 
			
		||||
				cm = ((opts.xlmeta||{}).Types||[])[val-1];
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case 0x01EE: /* 'BrtHLink' */
 | 
			
		||||
				var rel = rels['!id'][val.relId];
 | 
			
		||||
				if(rel) {
 | 
			
		||||
@ -15593,7 +15738,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
			case 0x041A: /* 'BrtCFVO14' */
 | 
			
		||||
			case 0x0289: /* 'BrtCellIgnoreEC' */
 | 
			
		||||
			case 0x0451: /* 'BrtCellIgnoreEC14' */
 | 
			
		||||
			case 0x0031: /* 'BrtCellMeta' */
 | 
			
		||||
			case 0x024D: /* 'BrtCellSmartTagProperty' */
 | 
			
		||||
			case 0x025F: /* 'BrtCellWatch' */
 | 
			
		||||
			case 0x0234: /* 'BrtColor' */
 | 
			
		||||
@ -16800,6 +16944,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) {
 | 
			
		||||
	return parse_xlink_xml((data/*:any*/), rel, name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_xlmeta(data, name/*:string*/, opts) {
 | 
			
		||||
	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts);
 | 
			
		||||
	return parse_xlmeta_xml((data/*:any*/), name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_wb(wb, name/*:string*/, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
 | 
			
		||||
}
 | 
			
		||||
@ -16829,6 +16978,10 @@ function write_cc(data, name:string, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
function write_xlmeta(name/*:string*/) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
 | 
			
		||||
}
 | 
			
		||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
 | 
			
		||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
 | 
			
		||||
function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) {
 | 
			
		||||
@ -19097,7 +19250,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder },
 | 
			
		||||
	/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF },
 | 
			
		||||
	/*::[*/0x0030/*::]*/: { n:"BrtStyle" },
 | 
			
		||||
	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" },
 | 
			
		||||
	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE },
 | 
			
		||||
	/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" },
 | 
			
		||||
	/*::[*/0x0033/*::]*/: { n:"BrtMdb" },
 | 
			
		||||
	/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" },
 | 
			
		||||
@ -19323,7 +19476,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" },
 | 
			
		||||
	/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" },
 | 
			
		||||
	/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" },
 | 
			
		||||
	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" },
 | 
			
		||||
	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
 | 
			
		||||
	/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" },
 | 
			
		||||
	/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" },
 | 
			
		||||
	/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" },
 | 
			
		||||
@ -19844,7 +19997,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" },
 | 
			
		||||
	/*::[*/0x0836/*::]*/: { n:"BrtDxf15" },
 | 
			
		||||
	/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" },
 | 
			
		||||
	/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" },
 | 
			
		||||
	/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" },
 | 
			
		||||
	/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" },
 | 
			
		||||
	/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" },
 | 
			
		||||
	/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" },
 | 
			
		||||
@ -19884,9 +20037,27 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" },
 | 
			
		||||
	/*::[*/0x0C00/*::]*/: { n:"BrtUid" },
 | 
			
		||||
	/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" },
 | 
			
		||||
	/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" },
 | 
			
		||||
	/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" },
 | 
			
		||||
	/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" },
 | 
			
		||||
	/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" },
 | 
			
		||||
	/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" },
 | 
			
		||||
	/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" },
 | 
			
		||||
	/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" },
 | 
			
		||||
	/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" },
 | 
			
		||||
	/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" },
 | 
			
		||||
	/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" },
 | 
			
		||||
	/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" },
 | 
			
		||||
	/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" },
 | 
			
		||||
	/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" },
 | 
			
		||||
	/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" },
 | 
			
		||||
	/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" },
 | 
			
		||||
	/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" },
 | 
			
		||||
	/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" },
 | 
			
		||||
	/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" },
 | 
			
		||||
	/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" },
 | 
			
		||||
	/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" },
 | 
			
		||||
	/*::[*/0xFFFF/*::]*/: { n:"" }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -22740,9 +22911,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
 | 
			
		||||
	var wbrelsi = dir.workbooks[0].lastIndexOf("/");
 | 
			
		||||
	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
 | 
			
		||||
	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
 | 
			
		||||
 | 
			
		||||
	if((dir.metadata || []).length >= 1) {
 | 
			
		||||
		/* TODO: MDX and other types of metadata */
 | 
			
		||||
		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Numbers iOS hack */
 | 
			
		||||
	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
 | 
			
		||||
	wsloop: for(i = 0; i != props.Worksheets; ++i) {
 | 
			
		||||
@ -22978,6 +23156,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta(f));
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -22986,7 +23169,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
	return zip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* this version does not reference XLSB write functions */
 | 
			
		||||
function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
	_shapeid = 1024;
 | 
			
		||||
	if(wb && !wb.SSF) {
 | 
			
		||||
@ -23108,6 +23291,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta_xml());
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -23161,6 +23349,7 @@ function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ {
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
 | 
			
		||||
	o.type = "binary";
 | 
			
		||||
	return read_plaintext(str, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23280,14 +23469,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
 | 
			
		||||
}
 | 
			
		||||
function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ {
 | 
			
		||||
	var oopts = {};
 | 
			
		||||
	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
 | 
			
		||||
	if(o.compression) oopts.compression = 'DEFLATE';
 | 
			
		||||
	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
 | 
			
		||||
	if(o.password) oopts.type = ftype;
 | 
			
		||||
	else switch(o.type) {
 | 
			
		||||
		case "base64": oopts.type = "base64"; break;
 | 
			
		||||
		case "binary": oopts.type = "string"; break;
 | 
			
		||||
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
 | 
			
		||||
		case "buffer":
 | 
			
		||||
		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
 | 
			
		||||
		case "file": oopts.type = ftype; break;
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
 | 
			
		||||
@ -23811,7 +24001,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* set array formula and flush related cells */
 | 
			
		||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) {
 | 
			
		||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) {
 | 
			
		||||
	var rng = typeof range != "string" ? range : safe_decode_range(range);
 | 
			
		||||
	var rngstr = typeof range == "string" ? range : encode_range(range);
 | 
			
		||||
	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
 | 
			
		||||
@ -23819,7 +24009,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri
 | 
			
		||||
		cell.t = 'n';
 | 
			
		||||
		cell.F = rngstr;
 | 
			
		||||
		delete cell.v;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) cell.f = formula;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) {
 | 
			
		||||
			cell.f = formula;
 | 
			
		||||
			if(dynamic) cell.D = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ws;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										310
									
								
								xlsx.js
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										310
									
								
								xlsx.js
									
									
									
										generated
									
									
									
								
							@ -4,7 +4,7 @@
 | 
			
		||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
 | 
			
		||||
var XLSX = {};
 | 
			
		||||
function make_xlsx_lib(XLSX){
 | 
			
		||||
XLSX.version = '0.18.2';
 | 
			
		||||
XLSX.version = '0.18.3';
 | 
			
		||||
var current_codepage = 1200, current_ansi = 1252;
 | 
			
		||||
/*global cptable:true, window */
 | 
			
		||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
 | 
			
		||||
@ -3114,7 +3114,7 @@ function write_dl(fname, payload, enc) {
 | 
			
		||||
	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
 | 
			
		||||
	if(typeof Deno !== 'undefined') {
 | 
			
		||||
		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
 | 
			
		||||
		if(enc) switch(enc) {
 | 
			
		||||
		if(enc && typeof payload == "string") switch(enc) {
 | 
			
		||||
			case "utf8": payload = new TextEncoder(enc).encode(payload); break;
 | 
			
		||||
			case "binary": payload = s2ab(payload); break;
 | 
			
		||||
			/* TODO: binary equivalent */
 | 
			
		||||
@ -4057,43 +4057,6 @@ function encode_range_xls(r, opts) {
 | 
			
		||||
	}
 | 
			
		||||
	return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
 | 
			
		||||
}
 | 
			
		||||
var OFFCRYPTO = {};
 | 
			
		||||
 | 
			
		||||
var make_offcrypto = function(O, _crypto) {
 | 
			
		||||
	var crypto;
 | 
			
		||||
	if(typeof _crypto !== 'undefined') crypto = _crypto;
 | 
			
		||||
	else if(typeof require !== 'undefined') {
 | 
			
		||||
		try { crypto = require('crypto'); }
 | 
			
		||||
		catch(e) { crypto = null; }
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	O.rc4 = function(key, data) {
 | 
			
		||||
		var S = new Array(256);
 | 
			
		||||
		var c = 0, i = 0, j = 0, t = 0;
 | 
			
		||||
		for(i = 0; i != 256; ++i) S[i] = i;
 | 
			
		||||
		for(i = 0; i != 256; ++i) {
 | 
			
		||||
			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
 | 
			
		||||
			t = S[i]; S[i] = S[j]; S[j] = t;
 | 
			
		||||
		}
 | 
			
		||||
		// $FlowIgnore
 | 
			
		||||
		i = j = 0; var out = new_raw_buf(data.length);
 | 
			
		||||
		for(c = 0; c != data.length; ++c) {
 | 
			
		||||
			i = (i + 1)&255;
 | 
			
		||||
			j = (j + S[i])%256;
 | 
			
		||||
			t = S[i]; S[i] = S[j]; S[j] = t;
 | 
			
		||||
			out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
 | 
			
		||||
		}
 | 
			
		||||
		return out;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	O.md5 = function(hex) {
 | 
			
		||||
		if(!crypto) throw new Error("Unsupported crypto");
 | 
			
		||||
		return crypto.createHash('md5').update(hex).digest('hex');
 | 
			
		||||
	};
 | 
			
		||||
};
 | 
			
		||||
/*global crypto:true */
 | 
			
		||||
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
 | 
			
		||||
 | 
			
		||||
function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
 | 
			
		||||
function encode_row(row) { return "" + (row + 1); }
 | 
			
		||||
function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
 | 
			
		||||
@ -4258,6 +4221,9 @@ function sheet_add_aoa(_ws, data, opts) {
 | 
			
		||||
}
 | 
			
		||||
function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
 | 
			
		||||
 | 
			
		||||
function parse_Int32LE(data) {
 | 
			
		||||
	return data.read_shift(4, 'i');
 | 
			
		||||
}
 | 
			
		||||
function write_UInt32LE(x, o) {
 | 
			
		||||
	if (!o) o = new_buf(4);
 | 
			
		||||
	o.write_shift(4, x);
 | 
			
		||||
@ -4923,8 +4889,8 @@ var ct2type/*{[string]:string}*/ = ({
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
 | 
			
		||||
 | 
			
		||||
	/* Metadata */
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "TODO",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "metadata",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
 | 
			
		||||
 | 
			
		||||
	/* PivotCache */
 | 
			
		||||
	"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
 | 
			
		||||
@ -5041,6 +5007,10 @@ var CT_LIST = (function(){
 | 
			
		||||
			xlsx: "application/vnd.ms-excel.macrosheet+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.macrosheet"
 | 
			
		||||
		},
 | 
			
		||||
		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.sheetMetadata"
 | 
			
		||||
		},
 | 
			
		||||
		styles: { /* Styles */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.styles"
 | 
			
		||||
@ -5060,7 +5030,7 @@ function new_ct() {
 | 
			
		||||
		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
 | 
			
		||||
		rels:[], strs:[], comments:[], links:[],
 | 
			
		||||
		coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [], metadata: [],
 | 
			
		||||
		TODO:[], xmlns: "" });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5159,6 +5129,7 @@ function write_ct(ct, opts) {
 | 
			
		||||
	f3('vba');
 | 
			
		||||
	f3('comments');
 | 
			
		||||
	f3('drawings');
 | 
			
		||||
	f2('metadata');
 | 
			
		||||
	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
@ -5225,7 +5196,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
 | 
			
		||||
function add_rels(rels, rId, f, type, relobj, targetmode) {
 | 
			
		||||
	if(!relobj) relobj = {};
 | 
			
		||||
	if(!rels['!id']) rels['!id'] = {};
 | 
			
		||||
	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
 | 
			
		||||
	if(!rels['!idx']) rels['!idx'] = 1;
 | 
			
		||||
	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */}
 | 
			
		||||
	rels['!idx'] = rId + 1;
 | 
			
		||||
	relobj.Id = 'rId' + rId;
 | 
			
		||||
	relobj.Type = type;
 | 
			
		||||
	relobj.Target = f;
 | 
			
		||||
@ -11209,6 +11182,157 @@ function update_xfext(xf, xfext) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
function parse_xlmeta_xml(data, name, opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  if (!data)
 | 
			
		||||
    return out;
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  data.replace(tagregex, function(x, idx) {
 | 
			
		||||
    var y = parsexmltag(x);
 | 
			
		||||
    switch (strip_ns(y[0])) {
 | 
			
		||||
      case "<?xml":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadata":
 | 
			
		||||
      case "</metadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataTypes":
 | 
			
		||||
      case "</metadataTypes>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataType":
 | 
			
		||||
        out.Types.push({ name: y.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case "<futureMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</futureMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<rc":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</rc>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<cellMetadata":
 | 
			
		||||
      case "</cellMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<valueMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</valueMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<extLst":
 | 
			
		||||
      case "<extLst>":
 | 
			
		||||
      case "</extLst>":
 | 
			
		||||
      case "<extLst/>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<ext":
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case "</ext>":
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (!pass && opts.WTF)
 | 
			
		||||
          throw new Error("unrecognized " + y[0] + " in metadata");
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_xml() {
 | 
			
		||||
  var o = [XML_HEADER];
 | 
			
		||||
  o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>');
 | 
			
		||||
  return o.join("");
 | 
			
		||||
}
 | 
			
		||||
function parse_BrtMdtinfo(data, length) {
 | 
			
		||||
  return {
 | 
			
		||||
    flags: data.read_shift(4),
 | 
			
		||||
    version: data.read_shift(4),
 | 
			
		||||
    name: parse_XLWideString(data, length - 8)
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdtinfo(data) {
 | 
			
		||||
  var o = new_buf(12 + 2 * data.name.length);
 | 
			
		||||
  o.write_shift(4, data.flags);
 | 
			
		||||
  o.write_shift(4, data.version);
 | 
			
		||||
  write_XLWideString(data.name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdb(mdb) {
 | 
			
		||||
  var o = new_buf(4 + 8 * mdb.length);
 | 
			
		||||
  o.write_shift(4, mdb.length);
 | 
			
		||||
  for (var i = 0; i < mdb.length; ++i) {
 | 
			
		||||
    o.write_shift(4, mdb[i][0]);
 | 
			
		||||
    o.write_shift(4, mdb[i][1]);
 | 
			
		||||
  }
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsfmd(cnt, name) {
 | 
			
		||||
  var o = new_buf(8 + 2 * name.length);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  write_XLWideString(name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsmdb(cnt, cm) {
 | 
			
		||||
  var o = new_buf(8);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  o.write_shift(4, cm ? 1 : 0);
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function parse_xlmeta_bin(data, name, _opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  var opts = _opts || {};
 | 
			
		||||
  var state = [];
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  recordhopper(data, function(val, R_n, RT) {
 | 
			
		||||
    switch (RT) {
 | 
			
		||||
      case 335:
 | 
			
		||||
        out.Types.push({ name: val.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case 51:
 | 
			
		||||
        break;
 | 
			
		||||
      case 35:
 | 
			
		||||
        state.push(R_n);
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case 36:
 | 
			
		||||
        state.pop();
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if ((R_n || "").indexOf("Begin") > 0) {
 | 
			
		||||
        } else if ((R_n || "").indexOf("End") > 0) {
 | 
			
		||||
        } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
 | 
			
		||||
          throw new Error("Unexpected record " + RT + " " + R_n);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_bin() {
 | 
			
		||||
  var ba = buf_array();
 | 
			
		||||
  write_record(ba, "BrtBeginMetadata");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
 | 
			
		||||
  write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
 | 
			
		||||
    name: "XLDAPR",
 | 
			
		||||
    version: 12e4,
 | 
			
		||||
    flags: 3496657072
 | 
			
		||||
  }));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdtinfo");
 | 
			
		||||
  write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
 | 
			
		||||
  write_record(ba, "BrtBeginFmd");
 | 
			
		||||
  write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
 | 
			
		||||
  write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
 | 
			
		||||
  write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
 | 
			
		||||
  write_record(ba, "BrtFRTEnd");
 | 
			
		||||
  write_record(ba, "BrtEndFmd");
 | 
			
		||||
  write_record(ba, "BrtEndEsfmd");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
 | 
			
		||||
  write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdb");
 | 
			
		||||
  write_record(ba, "BrtEndMetadata");
 | 
			
		||||
  return ba.end();
 | 
			
		||||
}
 | 
			
		||||
/* 18.6 Calculation Chain */
 | 
			
		||||
function parse_cc_xml(data) {
 | 
			
		||||
	var d = [];
 | 
			
		||||
@ -12534,7 +12658,7 @@ ixti = f[1][1]; r = f[1][2];
 | 
			
		||||
				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
 | 
			
		||||
				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
 | 
			
		||||
				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
 | 
			
		||||
				stack.push(name);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
@ -14432,6 +14556,7 @@ function write_ws_xml_cell(cell, ref, ws, opts) {
 | 
			
		||||
	}
 | 
			
		||||
	if(cell.l) ws['!links'].push([ref, cell.l]);
 | 
			
		||||
	if(cell.c) ws['!comments'].push([ref, cell.c]);
 | 
			
		||||
	if(cell.D) o.cm = 1;
 | 
			
		||||
	return writextag('c', v, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14608,6 +14733,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
 | 
			
		||||
			}
 | 
			
		||||
			safe_format(p, fmtid, fillid, opts, themes, styles);
 | 
			
		||||
			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
 | 
			
		||||
			if(tag.cm && opts.xlmeta) {
 | 
			
		||||
				var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
 | 
			
		||||
				if(cm && cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
			}
 | 
			
		||||
			if(dense) {
 | 
			
		||||
				var _r = decode_cell(tag.r);
 | 
			
		||||
				if(!s[_r.r]) s[_r.r] = [];
 | 
			
		||||
@ -15321,6 +15450,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
 | 
			
		||||
	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
 | 
			
		||||
 | 
			
		||||
	var cm, vm;
 | 
			
		||||
 | 
			
		||||
	recordhopper(data, function ws_parse(val, R_n, RT) {
 | 
			
		||||
		if(end) return;
 | 
			
		||||
		switch(RT) {
 | 
			
		||||
@ -15378,6 +15509,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
					}
 | 
			
		||||
					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;
 | 
			
		||||
@ -15385,12 +15517,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
				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); }
 | 
			
		||||
				}
 | 
			
		||||
				if(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x0001: /* 'BrtCellBlank' */
 | 
			
		||||
			case 0x000C: /* 'BrtShortBlank' */
 | 
			
		||||
				if(!opts.sheetStubs || pass) break;
 | 
			
		||||
				p = ({t:'z',v:undefined});
 | 
			
		||||
				p = ({t:'z',v:void 0});
 | 
			
		||||
				C = val[0].c == -1 ? C + 1 : val[0].c;
 | 
			
		||||
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
 | 
			
		||||
				else s[encode_col(C) + rr] = p;
 | 
			
		||||
@ -15398,11 +15535,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
				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(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x00B0: /* 'BrtMergeCell' */
 | 
			
		||||
				merges.push(val); break;
 | 
			
		||||
 | 
			
		||||
			case 0x0031: { /* 'BrtCellMeta' */
 | 
			
		||||
				cm = ((opts.xlmeta||{}).Types||[])[val-1];
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case 0x01EE: /* 'BrtHLink' */
 | 
			
		||||
				var rel = rels['!id'][val.relId];
 | 
			
		||||
				if(rel) {
 | 
			
		||||
@ -15490,7 +15636,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
 | 
			
		||||
			case 0x041A: /* 'BrtCFVO14' */
 | 
			
		||||
			case 0x0289: /* 'BrtCellIgnoreEC' */
 | 
			
		||||
			case 0x0451: /* 'BrtCellIgnoreEC14' */
 | 
			
		||||
			case 0x0031: /* 'BrtCellMeta' */
 | 
			
		||||
			case 0x024D: /* 'BrtCellSmartTagProperty' */
 | 
			
		||||
			case 0x025F: /* 'BrtCellWatch' */
 | 
			
		||||
			case 0x0234: /* 'BrtColor' */
 | 
			
		||||
@ -16695,6 +16840,11 @@ function parse_xlink(data, rel, name, opts) {
 | 
			
		||||
	return parse_xlink_xml((data), rel, name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_xlmeta(data, name, opts) {
 | 
			
		||||
	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data), name, opts);
 | 
			
		||||
	return parse_xlmeta_xml((data), name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_wb(wb, name, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
 | 
			
		||||
}
 | 
			
		||||
@ -16724,6 +16874,10 @@ function write_cc(data, name:string, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
function write_xlmeta(name) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
 | 
			
		||||
}
 | 
			
		||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
 | 
			
		||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
 | 
			
		||||
function xlml_parsexmltag(tag, skip_root) {
 | 
			
		||||
@ -18980,7 +19134,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
0x002E: { n:"BrtBorder", f:parse_BrtBorder },
 | 
			
		||||
0x002F: { n:"BrtXF", f:parse_BrtXF },
 | 
			
		||||
0x0030: { n:"BrtStyle" },
 | 
			
		||||
0x0031: { n:"BrtCellMeta" },
 | 
			
		||||
0x0031: { n:"BrtCellMeta", f:parse_Int32LE },
 | 
			
		||||
0x0032: { n:"BrtValueMeta" },
 | 
			
		||||
0x0033: { n:"BrtMdb" },
 | 
			
		||||
0x0034: { n:"BrtBeginFmd" },
 | 
			
		||||
@ -19206,7 +19360,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
0x014C: { n:"BrtBeginMetadata" },
 | 
			
		||||
0x014D: { n:"BrtEndMetadata" },
 | 
			
		||||
0x014E: { n:"BrtBeginEsmdtinfo" },
 | 
			
		||||
0x014F: { n:"BrtMdtinfo" },
 | 
			
		||||
0x014F: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
 | 
			
		||||
0x0150: { n:"BrtEndEsmdtinfo" },
 | 
			
		||||
0x0151: { n:"BrtBeginEsmdb" },
 | 
			
		||||
0x0152: { n:"BrtEndEsmdb" },
 | 
			
		||||
@ -19727,7 +19881,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
0x0835: { n:"BrtEndTimelineStyleElements" },
 | 
			
		||||
0x0836: { n:"BrtDxf15" },
 | 
			
		||||
0x0837: { n:"BrtBeginDxfs15" },
 | 
			
		||||
0x0838: { n:"brtEndDxfs15" },
 | 
			
		||||
0x0838: { n:"BrtEndDxfs15" },
 | 
			
		||||
0x0839: { n:"BrtSlicerCacheHideItemsWithNoData" },
 | 
			
		||||
0x083A: { n:"BrtBeginItemUniqueNames" },
 | 
			
		||||
0x083B: { n:"BrtEndItemUniqueNames" },
 | 
			
		||||
@ -19767,9 +19921,27 @@ var XLSBRecordEnum = {
 | 
			
		||||
0x085D: { n:"BrtModelTimeGroupingCalcCol" },
 | 
			
		||||
0x0C00: { n:"BrtUid" },
 | 
			
		||||
0x0C01: { n:"BrtRevisionPtr" },
 | 
			
		||||
0x13e7: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
0x13e8: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
0x13e9: { n:"BrtCalcFeature" },
 | 
			
		||||
0x1000: { n:"BrtBeginDynamicArrayPr" },
 | 
			
		||||
0x1001: { n:"BrtEndDynamicArrayPr" },
 | 
			
		||||
0x138A: { n:"BrtBeginRichValueBlock" },
 | 
			
		||||
0x138B: { n:"BrtEndRichValueBlock" },
 | 
			
		||||
0x13D9: { n:"BrtBeginRichFilters" },
 | 
			
		||||
0x13DA: { n:"BrtEndRichFilters" },
 | 
			
		||||
0x13DB: { n:"BrtRichFilter" },
 | 
			
		||||
0x13DC: { n:"BrtBeginRichFilterColumn" },
 | 
			
		||||
0x13DD: { n:"BrtEndRichFilterColumn" },
 | 
			
		||||
0x13DE: { n:"BrtBeginCustomRichFilters" },
 | 
			
		||||
0x13DF: { n:"BrtEndCustomRichFilters" },
 | 
			
		||||
0x13E0: { n:"BrtCustomRichFilter" },
 | 
			
		||||
0x13E1: { n:"BrtTop10RichFilter" },
 | 
			
		||||
0x13E2: { n:"BrtDynamicRichFilter" },
 | 
			
		||||
0x13E4: { n:"BrtBeginRichSortCondition" },
 | 
			
		||||
0x13E5: { n:"BrtEndRichSortCondition" },
 | 
			
		||||
0x13E6: { n:"BrtRichFilterDateGroupItem" },
 | 
			
		||||
0x13E7: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
0x13E8: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
0x13E9: { n:"BrtCalcFeature" },
 | 
			
		||||
0x13EB: { n:"BrtExternalLinksPr" },
 | 
			
		||||
0xFFFF: { n:"" }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -22622,9 +22794,16 @@ function parse_zip(zip, opts) {
 | 
			
		||||
	var wbrelsi = dir.workbooks[0].lastIndexOf("/");
 | 
			
		||||
	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
 | 
			
		||||
	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
 | 
			
		||||
 | 
			
		||||
	if((dir.metadata || []).length >= 1) {
 | 
			
		||||
		/* TODO: MDX and other types of metadata */
 | 
			
		||||
		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Numbers iOS hack */
 | 
			
		||||
	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
 | 
			
		||||
	wsloop: for(i = 0; i != props.Worksheets; ++i) {
 | 
			
		||||
@ -22857,6 +23036,11 @@ f = "docProps/app.xml";
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta(f));
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -22865,7 +23049,7 @@ f = "docProps/app.xml";
 | 
			
		||||
	return zip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* this version does not reference XLSB write functions */
 | 
			
		||||
function write_zip_xlsx(wb, opts) {
 | 
			
		||||
	_shapeid = 1024;
 | 
			
		||||
	if(wb && !wb.SSF) {
 | 
			
		||||
@ -22986,6 +23170,11 @@ f = "docProps/app.xml";
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta_xml());
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -23039,6 +23228,7 @@ function read_plaintext_raw(data, o) {
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
 | 
			
		||||
	o.type = "binary";
 | 
			
		||||
	return read_plaintext(str, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23157,14 +23347,15 @@ function write_zip_typeXLSX(wb, opts) {
 | 
			
		||||
}
 | 
			
		||||
function write_zip_denouement(z, o) {
 | 
			
		||||
	var oopts = {};
 | 
			
		||||
	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
 | 
			
		||||
	if(o.compression) oopts.compression = 'DEFLATE';
 | 
			
		||||
	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
 | 
			
		||||
	if(o.password) oopts.type = ftype;
 | 
			
		||||
	else switch(o.type) {
 | 
			
		||||
		case "base64": oopts.type = "base64"; break;
 | 
			
		||||
		case "binary": oopts.type = "string"; break;
 | 
			
		||||
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
 | 
			
		||||
		case "buffer":
 | 
			
		||||
		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
 | 
			
		||||
		case "file": oopts.type = ftype; break;
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
 | 
			
		||||
@ -23682,7 +23873,7 @@ utils.cell_add_comment = function(cell, text, author) {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* set array formula and flush related cells */
 | 
			
		||||
utils.sheet_set_array_formula = function(ws, range, formula) {
 | 
			
		||||
utils.sheet_set_array_formula = function(ws, range, formula, dynamic) {
 | 
			
		||||
	var rng = typeof range != "string" ? range : safe_decode_range(range);
 | 
			
		||||
	var rngstr = typeof range == "string" ? range : encode_range(range);
 | 
			
		||||
	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
 | 
			
		||||
@ -23690,7 +23881,10 @@ utils.sheet_set_array_formula = function(ws, range, formula) {
 | 
			
		||||
		cell.t = 'n';
 | 
			
		||||
		cell.F = rngstr;
 | 
			
		||||
		delete cell.v;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) cell.f = formula;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) {
 | 
			
		||||
			cell.f = formula;
 | 
			
		||||
			if(dynamic) cell.D = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ws;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										989
									
								
								xlsx.mini.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										989
									
								
								xlsx.mini.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										273
									
								
								xlsx.mjs
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										273
									
								
								xlsx.mjs
									
									
									
										generated
									
									
									
								
							@ -3,7 +3,7 @@
 | 
			
		||||
/*exported XLSX */
 | 
			
		||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
 | 
			
		||||
var XLSX = {};
 | 
			
		||||
XLSX.version = '0.18.2';
 | 
			
		||||
XLSX.version = '0.18.3';
 | 
			
		||||
var current_codepage = 1200, current_ansi = 1252;
 | 
			
		||||
 | 
			
		||||
var VALID_ANSI = [ 874, 932, 936, 949, 950, 10000 ];
 | 
			
		||||
@ -3186,7 +3186,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
 | 
			
		||||
	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
 | 
			
		||||
	if(typeof Deno !== 'undefined') {
 | 
			
		||||
		/* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
 | 
			
		||||
		if(enc) switch(enc) {
 | 
			
		||||
		if(enc && typeof payload == "string") switch(enc) {
 | 
			
		||||
			case "utf8": payload = new TextEncoder(enc).encode(payload); break;
 | 
			
		||||
			case "binary": payload = s2ab(payload); break;
 | 
			
		||||
			/* TODO: binary equivalent */
 | 
			
		||||
@ -4310,6 +4310,9 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
 | 
			
		||||
}
 | 
			
		||||
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); }
 | 
			
		||||
 | 
			
		||||
function parse_Int32LE(data) {
 | 
			
		||||
	return data.read_shift(4, 'i');
 | 
			
		||||
}
 | 
			
		||||
function write_UInt32LE(x/*:number*/, o) {
 | 
			
		||||
	if (!o) o = new_buf(4);
 | 
			
		||||
	o.write_shift(4, x);
 | 
			
		||||
@ -4975,8 +4978,8 @@ var ct2type/*{[string]:string}*/ = ({
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
 | 
			
		||||
 | 
			
		||||
	/* Metadata */
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "TODO",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
 | 
			
		||||
	"application/vnd.ms-excel.sheetMetadata": "metadata",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata",
 | 
			
		||||
 | 
			
		||||
	/* PivotCache */
 | 
			
		||||
	"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
 | 
			
		||||
@ -5093,6 +5096,10 @@ var CT_LIST = (function(){
 | 
			
		||||
			xlsx: "application/vnd.ms-excel.macrosheet+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.macrosheet"
 | 
			
		||||
		},
 | 
			
		||||
		metadata: { /* Metadata (Stock/Geography and Dynamic Array) */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.sheetMetadata"
 | 
			
		||||
		},
 | 
			
		||||
		styles: { /* Styles */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.styles"
 | 
			
		||||
@ -5112,7 +5119,7 @@ function new_ct()/*:any*/ {
 | 
			
		||||
		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
 | 
			
		||||
		rels:[], strs:[], comments:[], links:[],
 | 
			
		||||
		coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [],
 | 
			
		||||
		calcchains:[], vba: [], drawings: [], metadata: [],
 | 
			
		||||
		TODO:[], xmlns: "" }/*:any*/);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -5211,6 +5218,7 @@ function write_ct(ct, opts)/*:string*/ {
 | 
			
		||||
	f3('vba');
 | 
			
		||||
	f3('comments');
 | 
			
		||||
	f3('drawings');
 | 
			
		||||
	f2('metadata');
 | 
			
		||||
	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
@ -5277,7 +5285,9 @@ var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
 | 
			
		||||
function add_rels(rels, rId/*:number*/, f, type, relobj, targetmode/*:?string*/)/*:number*/ {
 | 
			
		||||
	if(!relobj) relobj = {};
 | 
			
		||||
	if(!rels['!id']) rels['!id'] = {};
 | 
			
		||||
	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
 | 
			
		||||
	if(!rels['!idx']) rels['!idx'] = 1;
 | 
			
		||||
	if(rId < 0) for(rId = rels['!idx']; rels['!id']['rId' + rId]; ++rId){/* empty */}
 | 
			
		||||
	rels['!idx'] = rId + 1;
 | 
			
		||||
	relobj.Id = 'rId' + rId;
 | 
			
		||||
	relobj.Type = type;
 | 
			
		||||
	relobj.Target = f;
 | 
			
		||||
@ -11269,6 +11279,157 @@ function update_xfext(xf, xfext) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata";
 | 
			
		||||
function parse_xlmeta_xml(data, name, opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  if (!data)
 | 
			
		||||
    return out;
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  data.replace(tagregex, function(x, idx) {
 | 
			
		||||
    var y = parsexmltag(x);
 | 
			
		||||
    switch (strip_ns(y[0])) {
 | 
			
		||||
      case "<?xml":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadata":
 | 
			
		||||
      case "</metadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataTypes":
 | 
			
		||||
      case "</metadataTypes>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<metadataType":
 | 
			
		||||
        out.Types.push({ name: y.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case "<futureMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</futureMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</bk>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<rc":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</rc>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<cellMetadata":
 | 
			
		||||
      case "</cellMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<valueMetadata":
 | 
			
		||||
        break;
 | 
			
		||||
      case "</valueMetadata>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<extLst":
 | 
			
		||||
      case "<extLst>":
 | 
			
		||||
      case "</extLst>":
 | 
			
		||||
      case "<extLst/>":
 | 
			
		||||
        break;
 | 
			
		||||
      case "<ext":
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case "</ext>":
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if (!pass && opts.WTF)
 | 
			
		||||
          throw new Error("unrecognized " + y[0] + " in metadata");
 | 
			
		||||
    }
 | 
			
		||||
    return x;
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_xml() {
 | 
			
		||||
  var o = [XML_HEADER];
 | 
			
		||||
  o.push('<metadata xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:xlrd="http://schemas.microsoft.com/office/spreadsheetml/2017/richdata" xmlns:xda="http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray">\n  <metadataTypes count="1">\n    <metadataType name="XLDAPR" minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1" cellMeta="1"/>\n  </metadataTypes>\n  <futureMetadata name="XLDAPR" count="1">\n    <bk>\n      <extLst>\n        <ext uri="{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}">\n          <xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>\n        </ext>\n      </extLst>\n    </bk>\n  </futureMetadata>\n  <cellMetadata count="1">\n    <bk>\n      <rc t="1" v="0"/>\n    </bk>\n  </cellMetadata>\n</metadata>');
 | 
			
		||||
  return o.join("");
 | 
			
		||||
}
 | 
			
		||||
function parse_BrtMdtinfo(data, length) {
 | 
			
		||||
  return {
 | 
			
		||||
    flags: data.read_shift(4),
 | 
			
		||||
    version: data.read_shift(4),
 | 
			
		||||
    name: parse_XLWideString(data, length - 8)
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdtinfo(data) {
 | 
			
		||||
  var o = new_buf(12 + 2 * data.name.length);
 | 
			
		||||
  o.write_shift(4, data.flags);
 | 
			
		||||
  o.write_shift(4, data.version);
 | 
			
		||||
  write_XLWideString(data.name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtMdb(mdb) {
 | 
			
		||||
  var o = new_buf(4 + 8 * mdb.length);
 | 
			
		||||
  o.write_shift(4, mdb.length);
 | 
			
		||||
  for (var i = 0; i < mdb.length; ++i) {
 | 
			
		||||
    o.write_shift(4, mdb[i][0]);
 | 
			
		||||
    o.write_shift(4, mdb[i][1]);
 | 
			
		||||
  }
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsfmd(cnt, name) {
 | 
			
		||||
  var o = new_buf(8 + 2 * name.length);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  write_XLWideString(name, o);
 | 
			
		||||
  return o.slice(0, o.l);
 | 
			
		||||
}
 | 
			
		||||
function write_BrtBeginEsmdb(cnt, cm) {
 | 
			
		||||
  var o = new_buf(8);
 | 
			
		||||
  o.write_shift(4, cnt);
 | 
			
		||||
  o.write_shift(4, cm ? 1 : 0);
 | 
			
		||||
  return o;
 | 
			
		||||
}
 | 
			
		||||
function parse_xlmeta_bin(data, name, _opts) {
 | 
			
		||||
  var out = { Types: [] };
 | 
			
		||||
  var opts = _opts || {};
 | 
			
		||||
  var state = [];
 | 
			
		||||
  var pass = false;
 | 
			
		||||
  recordhopper(data, function(val, R_n, RT) {
 | 
			
		||||
    switch (RT) {
 | 
			
		||||
      case 335:
 | 
			
		||||
        out.Types.push({ name: val.name });
 | 
			
		||||
        break;
 | 
			
		||||
      case 51:
 | 
			
		||||
        break;
 | 
			
		||||
      case 35:
 | 
			
		||||
        state.push(R_n);
 | 
			
		||||
        pass = true;
 | 
			
		||||
        break;
 | 
			
		||||
      case 36:
 | 
			
		||||
        state.pop();
 | 
			
		||||
        pass = false;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        if ((R_n || "").indexOf("Begin") > 0) {
 | 
			
		||||
        } else if ((R_n || "").indexOf("End") > 0) {
 | 
			
		||||
        } else if (!pass || opts.WTF && state[state.length - 1] != "BrtFRTBegin")
 | 
			
		||||
          throw new Error("Unexpected record " + RT + " " + R_n);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  return out;
 | 
			
		||||
}
 | 
			
		||||
function write_xlmeta_bin() {
 | 
			
		||||
  var ba = buf_array();
 | 
			
		||||
  write_record(ba, "BrtBeginMetadata");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdtinfo", write_UInt32LE(1));
 | 
			
		||||
  write_record(ba, "BrtMdtinfo", write_BrtMdtinfo({
 | 
			
		||||
    name: "XLDAPR",
 | 
			
		||||
    version: 12e4,
 | 
			
		||||
    flags: 3496657072
 | 
			
		||||
  }));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdtinfo");
 | 
			
		||||
  write_record(ba, "BrtBeginEsfmd", write_BrtBeginEsfmd(1, "XLDAPR"));
 | 
			
		||||
  write_record(ba, "BrtBeginFmd");
 | 
			
		||||
  write_record(ba, "BrtFRTBegin", write_UInt32LE(514));
 | 
			
		||||
  write_record(ba, "BrtBeginDynamicArrayPr", write_UInt32LE(0));
 | 
			
		||||
  write_record(ba, "BrtEndDynamicArrayPr", writeuint16(1));
 | 
			
		||||
  write_record(ba, "BrtFRTEnd");
 | 
			
		||||
  write_record(ba, "BrtEndFmd");
 | 
			
		||||
  write_record(ba, "BrtEndEsfmd");
 | 
			
		||||
  write_record(ba, "BrtBeginEsmdb", write_BrtBeginEsmdb(1, true));
 | 
			
		||||
  write_record(ba, "BrtMdb", write_BrtMdb([[1, 0]]));
 | 
			
		||||
  write_record(ba, "BrtEndEsmdb");
 | 
			
		||||
  write_record(ba, "BrtEndMetadata");
 | 
			
		||||
  return ba.end();
 | 
			
		||||
}
 | 
			
		||||
/* 18.6 Calculation Chain */
 | 
			
		||||
function parse_cc_xml(data/*::, name, opts*/)/*:Array<any>*/ {
 | 
			
		||||
	var d = [];
 | 
			
		||||
@ -12595,7 +12756,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
 | 
			
		||||
				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
 | 
			
		||||
				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
 | 
			
		||||
				/* [MS-XLSB] 2.5.97.10 Ftab -- last verified 20220204 */
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn.") name = name.slice(6);
 | 
			
		||||
				if(name && name.slice(0,6) == "_xlfn." && !opts.xlfn) name = name.slice(6);
 | 
			
		||||
				stack.push(name);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
@ -14493,6 +14654,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
 | 
			
		||||
	}
 | 
			
		||||
	if(cell.l) ws['!links'].push([ref, cell.l]);
 | 
			
		||||
	if(cell.c) ws['!comments'].push([ref, cell.c]);
 | 
			
		||||
	if(cell.D) o.cm = 1;
 | 
			
		||||
	return writextag('c', v, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14669,6 +14831,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
 | 
			
		||||
			}
 | 
			
		||||
			safe_format(p, fmtid, fillid, opts, themes, styles);
 | 
			
		||||
			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
 | 
			
		||||
			if(tag.cm && opts.xlmeta) {
 | 
			
		||||
				var cm = (opts.xlmeta.Types||[])[+tag.cm-1];
 | 
			
		||||
				if(cm && cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
			}
 | 
			
		||||
			if(dense) {
 | 
			
		||||
				var _r = decode_cell(tag.r);
 | 
			
		||||
				if(!s[_r.r]) s[_r.r] = [];
 | 
			
		||||
@ -15383,6 +15549,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
 | 
			
		||||
	XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
 | 
			
		||||
 | 
			
		||||
	var cm, vm;
 | 
			
		||||
 | 
			
		||||
	recordhopper(data, function ws_parse(val, R_n, RT) {
 | 
			
		||||
		if(end) return;
 | 
			
		||||
		switch(RT) {
 | 
			
		||||
@ -15440,6 +15608,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
					}
 | 
			
		||||
					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;
 | 
			
		||||
@ -15447,12 +15616,17 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
				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); }
 | 
			
		||||
				}
 | 
			
		||||
				if(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x0001: /* 'BrtCellBlank' */
 | 
			
		||||
			case 0x000C: /* 'BrtShortBlank' */
 | 
			
		||||
				if(!opts.sheetStubs || pass) break;
 | 
			
		||||
				p = ({t:'z',v:undefined}/*:any*/);
 | 
			
		||||
				p = ({t:'z',v:void 0}/*:any*/);
 | 
			
		||||
				C = val[0].c == -1 ? C + 1 : val[0].c;
 | 
			
		||||
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
 | 
			
		||||
				else s[encode_col(C) + rr] = p;
 | 
			
		||||
@ -15460,11 +15634,20 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
				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(cm) {
 | 
			
		||||
					if(cm.name == 'XLDAPR') p.D = true;
 | 
			
		||||
					cm = void 0;
 | 
			
		||||
				}
 | 
			
		||||
				if(vm) vm = void 0;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case 0x00B0: /* 'BrtMergeCell' */
 | 
			
		||||
				merges.push(val); break;
 | 
			
		||||
 | 
			
		||||
			case 0x0031: { /* 'BrtCellMeta' */
 | 
			
		||||
				cm = ((opts.xlmeta||{}).Types||[])[val-1];
 | 
			
		||||
			} break;
 | 
			
		||||
 | 
			
		||||
			case 0x01EE: /* 'BrtHLink' */
 | 
			
		||||
				var rel = rels['!id'][val.relId];
 | 
			
		||||
				if(rel) {
 | 
			
		||||
@ -15552,7 +15735,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
 | 
			
		||||
			case 0x041A: /* 'BrtCFVO14' */
 | 
			
		||||
			case 0x0289: /* 'BrtCellIgnoreEC' */
 | 
			
		||||
			case 0x0451: /* 'BrtCellIgnoreEC14' */
 | 
			
		||||
			case 0x0031: /* 'BrtCellMeta' */
 | 
			
		||||
			case 0x024D: /* 'BrtCellSmartTagProperty' */
 | 
			
		||||
			case 0x025F: /* 'BrtCellWatch' */
 | 
			
		||||
			case 0x0234: /* 'BrtColor' */
 | 
			
		||||
@ -16759,6 +16941,11 @@ function parse_xlink(data, rel, name/*:string*/, opts) {
 | 
			
		||||
	return parse_xlink_xml((data/*:any*/), rel, name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_xlmeta(data, name/*:string*/, opts) {
 | 
			
		||||
	if(name.slice(-4)===".bin") return parse_xlmeta_bin((data/*:any*/), name, opts);
 | 
			
		||||
	return parse_xlmeta_xml((data/*:any*/), name, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_wb(wb, name/*:string*/, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
 | 
			
		||||
}
 | 
			
		||||
@ -16788,6 +16975,10 @@ function write_cc(data, name:string, opts) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
function write_xlmeta(name/*:string*/) {
 | 
			
		||||
	return (name.slice(-4)===".bin" ? write_xlmeta_bin : write_xlmeta_xml)();
 | 
			
		||||
}
 | 
			
		||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
 | 
			
		||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
 | 
			
		||||
function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) {
 | 
			
		||||
@ -19056,7 +19247,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder },
 | 
			
		||||
	/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF },
 | 
			
		||||
	/*::[*/0x0030/*::]*/: { n:"BrtStyle" },
 | 
			
		||||
	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" },
 | 
			
		||||
	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta", f:parse_Int32LE },
 | 
			
		||||
	/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" },
 | 
			
		||||
	/*::[*/0x0033/*::]*/: { n:"BrtMdb" },
 | 
			
		||||
	/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" },
 | 
			
		||||
@ -19282,7 +19473,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" },
 | 
			
		||||
	/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" },
 | 
			
		||||
	/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" },
 | 
			
		||||
	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" },
 | 
			
		||||
	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo", f:parse_BrtMdtinfo },
 | 
			
		||||
	/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" },
 | 
			
		||||
	/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" },
 | 
			
		||||
	/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" },
 | 
			
		||||
@ -19803,7 +19994,7 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" },
 | 
			
		||||
	/*::[*/0x0836/*::]*/: { n:"BrtDxf15" },
 | 
			
		||||
	/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" },
 | 
			
		||||
	/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" },
 | 
			
		||||
	/*::[*/0x0838/*::]*/: { n:"BrtEndDxfs15" },
 | 
			
		||||
	/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" },
 | 
			
		||||
	/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" },
 | 
			
		||||
	/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" },
 | 
			
		||||
@ -19843,9 +20034,27 @@ var XLSBRecordEnum = {
 | 
			
		||||
	/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" },
 | 
			
		||||
	/*::[*/0x0C00/*::]*/: { n:"BrtUid" },
 | 
			
		||||
	/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" },
 | 
			
		||||
	/*::[*/0x13e7/*::]*/: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13e8/*::]*/: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13e9/*::]*/: { n:"BrtCalcFeature" },
 | 
			
		||||
	/*::[*/0x1000/*::]*/: { n:"BrtBeginDynamicArrayPr" },
 | 
			
		||||
	/*::[*/0x1001/*::]*/: { n:"BrtEndDynamicArrayPr" },
 | 
			
		||||
	/*::[*/0x138A/*::]*/: { n:"BrtBeginRichValueBlock" },
 | 
			
		||||
	/*::[*/0x138B/*::]*/: { n:"BrtEndRichValueBlock" },
 | 
			
		||||
	/*::[*/0x13D9/*::]*/: { n:"BrtBeginRichFilters" },
 | 
			
		||||
	/*::[*/0x13DA/*::]*/: { n:"BrtEndRichFilters" },
 | 
			
		||||
	/*::[*/0x13DB/*::]*/: { n:"BrtRichFilter" },
 | 
			
		||||
	/*::[*/0x13DC/*::]*/: { n:"BrtBeginRichFilterColumn" },
 | 
			
		||||
	/*::[*/0x13DD/*::]*/: { n:"BrtEndRichFilterColumn" },
 | 
			
		||||
	/*::[*/0x13DE/*::]*/: { n:"BrtBeginCustomRichFilters" },
 | 
			
		||||
	/*::[*/0x13DF/*::]*/: { n:"BrtEndCustomRichFilters" },
 | 
			
		||||
	/*::[*/0x13E0/*::]*/: { n:"BrtCustomRichFilter" },
 | 
			
		||||
	/*::[*/0x13E1/*::]*/: { n:"BrtTop10RichFilter" },
 | 
			
		||||
	/*::[*/0x13E2/*::]*/: { n:"BrtDynamicRichFilter" },
 | 
			
		||||
	/*::[*/0x13E4/*::]*/: { n:"BrtBeginRichSortCondition" },
 | 
			
		||||
	/*::[*/0x13E5/*::]*/: { n:"BrtEndRichSortCondition" },
 | 
			
		||||
	/*::[*/0x13E6/*::]*/: { n:"BrtRichFilterDateGroupItem" },
 | 
			
		||||
	/*::[*/0x13E7/*::]*/: { n:"BrtBeginCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13E8/*::]*/: { n:"BrtEndCalcFeatures" },
 | 
			
		||||
	/*::[*/0x13E9/*::]*/: { n:"BrtCalcFeature" },
 | 
			
		||||
	/*::[*/0x13EB/*::]*/: { n:"BrtExternalLinksPr" },
 | 
			
		||||
	/*::[*/0xFFFF/*::]*/: { n:"" }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -22699,9 +22908,16 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
 | 
			
		||||
	var wbrelsi = dir.workbooks[0].lastIndexOf("/");
 | 
			
		||||
	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
 | 
			
		||||
	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
 | 
			
		||||
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile.replace(/_rels.*/, "s5s"));
 | 
			
		||||
 | 
			
		||||
	if((dir.metadata || []).length >= 1) {
 | 
			
		||||
		/* TODO: MDX and other types of metadata */
 | 
			
		||||
		opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* Numbers iOS hack */
 | 
			
		||||
	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
 | 
			
		||||
	wsloop: for(i = 0; i != props.Worksheets; ++i) {
 | 
			
		||||
@ -22937,6 +23153,11 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta(f));
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -22945,7 +23166,7 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
	return zip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* this version does not reference XLSB write functions */
 | 
			
		||||
function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
	_shapeid = 1024;
 | 
			
		||||
	if(wb && !wb.SSF) {
 | 
			
		||||
@ -23067,6 +23288,11 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
 | 
			
		||||
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/metadata." + wbext;
 | 
			
		||||
	zip_add_file(zip, f, write_xlmeta_xml());
 | 
			
		||||
	ct.metadata.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
 | 
			
		||||
 | 
			
		||||
	zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
 | 
			
		||||
@ -23120,6 +23346,7 @@ function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ {
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
 | 
			
		||||
	o.type = "binary";
 | 
			
		||||
	return read_plaintext(str, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23239,14 +23466,15 @@ function write_zip_typeXLSX(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
 | 
			
		||||
}
 | 
			
		||||
function write_zip_denouement(z/*:any*/, o/*:?WriteOpts*/)/*:any*/ {
 | 
			
		||||
	var oopts = {};
 | 
			
		||||
	var ftype = has_buf ? "nodebuffer" : (typeof Uint8Array !== "undefined" ? "array" : "string");
 | 
			
		||||
	if(o.compression) oopts.compression = 'DEFLATE';
 | 
			
		||||
	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
 | 
			
		||||
	if(o.password) oopts.type = ftype;
 | 
			
		||||
	else switch(o.type) {
 | 
			
		||||
		case "base64": oopts.type = "base64"; break;
 | 
			
		||||
		case "binary": oopts.type = "string"; break;
 | 
			
		||||
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
 | 
			
		||||
		case "buffer":
 | 
			
		||||
		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
 | 
			
		||||
		case "file": oopts.type = ftype; break;
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: /*::(*/{"nodebuffer": "buffer", "string": "binary"}/*:: :any)*/[oopts.type] || oopts.type, compression: !!o.compression}) : z.generate(oopts);
 | 
			
		||||
@ -23770,7 +23998,7 @@ utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?stri
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* set array formula and flush related cells */
 | 
			
		||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) {
 | 
			
		||||
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/, dynamic/*:boolean*/) {
 | 
			
		||||
	var rng = typeof range != "string" ? range : safe_decode_range(range);
 | 
			
		||||
	var rngstr = typeof range == "string" ? range : encode_range(range);
 | 
			
		||||
	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
 | 
			
		||||
@ -23778,7 +24006,10 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri
 | 
			
		||||
		cell.t = 'n';
 | 
			
		||||
		cell.F = rngstr;
 | 
			
		||||
		delete cell.v;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) cell.f = formula;
 | 
			
		||||
		if(R == rng.s.r && C == rng.s.c) {
 | 
			
		||||
			cell.f = formula;
 | 
			
		||||
			if(dynamic) cell.D = true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ws;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user