From 6a5be04e3d6cd40ee7abceef103184127d6d069e Mon Sep 17 00:00:00 2001 From: SheetJS Date: Fri, 9 Sep 2022 16:59:22 -0400 Subject: [PATCH] =?UTF-8?q?=C5=9A=E2=95=AB=C3=AA=C3=AB=CF=84=E2=8C=A1?= =?UTF-8?q?=C5=9B=20and=20=C5=A0=E2=95=AB=C4=9B=C3=A9=CF=84=E2=8C=A1=C5=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 2 +- bits/23_binutils.js | 2 +- bits/40_harb.js | 11 +++++++++-- test.js | 10 ++++++++++ test.mjs | 14 ++++++++++++-- test.mts | 14 ++++++++++++-- test.ts | 14 ++++++++++++-- hotcross.mjs => testbun.mjs | 0 testnocp.ts | 14 ++++++++++++-- tests/core.js | 10 ++++++++++ types/index.d.ts | 21 ++++++++++++++++++++- xlsx.flow.js | 13 ++++++++++--- xlsx.js | 13 ++++++++++--- xlsx.mjs | 13 ++++++++++--- 14 files changed, 129 insertions(+), 22 deletions(-) rename hotcross.mjs => testbun.mjs (100%) diff --git a/Makefile b/Makefile index 07427e0..fb4b589 100644 --- a/Makefile +++ b/Makefile @@ -148,7 +148,7 @@ test.ts: test.mts node -pe 'var data = fs.readFileSync("'$<'", "utf8"); data.split("\n").map(function(l) { return l.replace(/^describe\((.*?)function\(\)/, "Deno.test($$1async function(t)").replace(/\b(?:it|describe)\((.*?)function\(\)/g, "await t.step($$1async function(t)").replace("assert.ok", "assert.assert"); }).join("\n")' > $@ .PHONY: test-bun -test-bun: hotcross.mjs ## Run Bun test suite +test-bun: testbun.mjs ## Run Bun test suite bun $< .PHONY: test-deno diff --git a/bits/23_binutils.js b/bits/23_binutils.js index d953355..2dd0838 100644 --- a/bits/23_binutils.js +++ b/bits/23_binutils.js @@ -191,7 +191,7 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/ } size = val.length; } else if(typeof $cptable !== 'undefined' && f == 'cpstr') { - cpp = $cptable.utils.encode(current_ansi, val); + cpp = $cptable.utils.encode(current_codepage, val); /* replace null bytes with _ when relevant */ if(cpp.length == val.length) for(i = 0; i < val.length; ++i) if(cpp[i] == 0 && val.charCodeAt(i) != 0) cpp[i] = 0x5F; if(cpp.length == 2 * val.length) for(i = 0; i < val.length; ++i) if(cpp[2*i] == 0 && cpp[2*i+1] == 0 && val.charCodeAt(i) != 0) cpp[2*i] = 0x5F; diff --git a/bits/40_harb.js b/bits/40_harb.js index 7ed7b6e..7c7de98 100644 --- a/bits/40_harb.js +++ b/bits/40_harb.js @@ -1,4 +1,3 @@ -/* from js-harb (C) 2014-present SheetJS */ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; var DBF = /*#__PURE__*/(function() { var dbf_codepage_map = { @@ -247,6 +246,7 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ { var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 }; function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { var o = opts || {}; + var old_cp = current_codepage; if(+o.codepage >= 0) set_cp(+o.codepage); if(o.type == "string") throw new Error("Cannot write DBF to JS string"); var ba = buf_array(); @@ -309,11 +309,17 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { h.write_shift(2, 296 + 32 * hcnt); h.write_shift(2, rlen); for(i=0; i < 4; ++i) h.write_shift(4, 0); - h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[/*::String(*/current_ansi/*::)*/] || 0x03)<<8)); + var cp = +dbf_reverse_map[/*::String(*/current_codepage/*::)*/] || 0x03; + h.write_shift(4, 0x00000000 | (cp<<8)); + if(dbf_codepage_map[cp] != +o.codepage) { + console.error("DBF Unsupported codepage " + current_codepage + ", using 1252"); + current_codepage = 1252; + } for(i = 0, j = 0; i < headers.length; ++i) { if(headers[i] == null) continue; var hf = ba.next(32); + /* TODO: test how applications handle non-ASCII field names */ var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11); hf.write_shift(1, _f, "sbcs"); hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs"); @@ -362,6 +368,7 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { } // data } + current_codepage = old_cp; ba.next(1).write_shift(1, 0x1A); return ba.end(); } diff --git a/test.js b/test.js index ef61f38..5213183 100644 --- a/test.js +++ b/test.js @@ -2399,6 +2399,16 @@ describe('dbf', function() { ["I2", "v", true], ["L2", "v", "SheetJS"] ].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); }); }); + if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() { + [ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) { + var book = X.utils.book_new(); + var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]); + X.utils.book_append_sheet(book, sheet, "sheet1"); + var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]}); + var wb = X.read(data, {type: TYPE}); + assert.equal(wb.Sheets.Sheet1.B2.v, r[1]); + }); + }); }); var JSDOM = null; // $FlowIgnore diff --git a/test.mjs b/test.mjs index 8b2a2dc..fa2812d 100644 --- a/test.mjs +++ b/test.mjs @@ -2204,14 +2204,14 @@ describe('CSV', function() { ["3a", "3 a", "3 a-1"], ["3b", "3 b", "3 b-1"], ["3p", "3 P", "3 p-1"] - ] + ]; var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]); assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]); } assert.equal(get_cell(ws, "B2").v, "3 b"); - var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3); + var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3); var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15); ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { @@ -2385,6 +2385,16 @@ describe('dbf', function() { ["I2", "v", true], ["L2", "v", "SheetJS"] ].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); }); }); + if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() { + [ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) { + var book = X.utils.book_new(); + var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]); + X.utils.book_append_sheet(book, sheet, "sheet1"); + var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]}); + var wb = X.read(data, {type: TYPE}); + assert.equal(wb.Sheets.Sheet1.B2.v, r[1]); + }); + }); }); import { JSDOM } from 'jsdom'; var domtest = true; diff --git a/test.mts b/test.mts index f57df05..9f3a125 100644 --- a/test.mts +++ b/test.mts @@ -2160,14 +2160,14 @@ describe('CSV', function() { ["3a", "3 a", "3 a-1"], ["3b", "3 b", "3 b-1"], ["3p", "3 P", "3 p-1"], - ] + ]; var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]); assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]); } assert.equal(get_cell(ws, "B2").v, "3 b"); - var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3); + var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3); var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15); ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { @@ -2326,6 +2326,16 @@ describe('dbf', function() { ["I2", "v", true], ["L2", "v", "SheetJS"] ] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); }); }); + it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() { + ([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) { + var book = X.utils.book_new(); + var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]); + X.utils.book_append_sheet(book, sheet, "sheet1"); + var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]}); + var wb = X.read(data, {type: TYPE}); + assert.equal(wb.Sheets.Sheet1.B2.v, r[1]); + }); + }); }); import { JSDOM } from 'jsdom'; var domtest = false; // error: Error: Not implemented: isContext diff --git a/test.ts b/test.ts index b050ab4..4ee7324 100644 --- a/test.ts +++ b/test.ts @@ -2160,14 +2160,14 @@ Deno.test('CSV', async function(t) { ["3a", "3 a", "3 a-1"], ["3b", "3 b", "3 b-1"], ["3p", "3 P", "3 p-1"], - ] + ]; var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]); assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]); } assert.equal(get_cell(ws, "B2").v, "3 b"); - var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3); + var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3); var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15); ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { @@ -2326,6 +2326,16 @@ Deno.test('dbf', async function(t) { ["I2", "v", true], ["L2", "v", "SheetJS"] ] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); }); }); + await t.step("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", async function(t) { + ([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) { + var book = X.utils.book_new(); + var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]); + X.utils.book_append_sheet(book, sheet, "sheet1"); + var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]}); + var wb = X.read(data, {type: TYPE}); + assert.equal(wb.Sheets.Sheet1.B2.v, r[1]); + }); + }); }); import { JSDOM } from 'jsdom'; var domtest = false; // error: Error: Not implemented: isContext diff --git a/hotcross.mjs b/testbun.mjs similarity index 100% rename from hotcross.mjs rename to testbun.mjs diff --git a/testnocp.ts b/testnocp.ts index 43c706a..2d26e58 100644 --- a/testnocp.ts +++ b/testnocp.ts @@ -2159,14 +2159,14 @@ Deno.test('CSV', async function(t) { ["3a", "3 a", "3 a-1"], ["3b", "3 b", "3 b-1"], ["3p", "3 P", "3 p-1"], - ] + ]; var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]); assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]); } assert.equal(get_cell(ws, "B2").v, "3 b"); - var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3); + var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3); var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15); ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1; for(var R = 0; R < 3; ++R) { @@ -2325,6 +2325,16 @@ Deno.test('dbf', async function(t) { ["I2", "v", true], ["L2", "v", "SheetJS"] ] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); }); }); + if(false) await t.step("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", async function(t) { + ([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) { + var book = X.utils.book_new(); + var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]); + X.utils.book_append_sheet(book, sheet, "sheet1"); + var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]}); + var wb = X.read(data, {type: TYPE}); + assert.equal(wb.Sheets.Sheet1.B2.v, r[1]); + }); + }); }); import { JSDOM } from 'jsdom'; var domtest = false; // error: Error: Not implemented: isContext diff --git a/tests/core.js b/tests/core.js index 5719a2d..8cf0a3b 100644 --- a/tests/core.js +++ b/tests/core.js @@ -2398,6 +2398,16 @@ describe('dbf', function() { ["I2", "v", true], ["L2", "v", "SheetJS"] ].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); }); }); + if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() { + [ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) { + var book = X.utils.book_new(); + var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]); + X.utils.book_append_sheet(book, sheet, "sheet1"); + var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]}); + var wb = X.read(data, {type: TYPE}); + assert.equal(wb.Sheets.Sheet1.B2.v, r[1]); + }); + }); }); var JSDOM = null; // $FlowIgnore diff --git a/types/index.d.ts b/types/index.d.ts index ebbed34..75423ac 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -144,7 +144,15 @@ export interface ParsingOptions extends CommonOptions { /** Input data encoding */ type?: 'base64' | 'binary' | 'buffer' | 'file' | 'array' | 'string'; - /** Default codepage */ + /** + * Default codepage for legacy files + * + * This requires encoding support to be loaded. It is automatically loaded + * in `xlsx.full.min.js` and in CommonJS / Extendscript, but an extra step + * is required in React / Angular / Webpack ESM deployments. + * + * Check the relevant guide https://docs.sheetjs.com/docs/getting-started/ + */ codepage?: number; /** @@ -261,6 +269,17 @@ export interface WritingOptions extends CommonOptions, SheetOption { /** Override workbook properties on save */ Props?: Properties; + /** + * Desired codepage for legacy file formats + * + * This requires encoding support to be loaded. It is automatically loaded + * in `xlsx.full.min.js` and in CommonJS / Extendscript, but an extra step + * is required in React / Angular / Webpack / ESM deployments. + * + * Check the relevant guide https://docs.sheetjs.com/docs/getting-started/ + */ + codepage?: number; + /** Base64 encoding of NUMBERS base for exports */ numbers?: string; } diff --git a/xlsx.flow.js b/xlsx.flow.js index e5bdab7..d2be395 100644 --- a/xlsx.flow.js +++ b/xlsx.flow.js @@ -4087,7 +4087,7 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/ } size = val.length; } else if(typeof $cptable !== 'undefined' && f == 'cpstr') { - cpp = $cptable.utils.encode(current_ansi, val); + cpp = $cptable.utils.encode(current_codepage, val); /* replace null bytes with _ when relevant */ if(cpp.length == val.length) for(i = 0; i < val.length; ++i) if(cpp[i] == 0 && val.charCodeAt(i) != 0) cpp[i] = 0x5F; if(cpp.length == 2 * val.length) for(i = 0; i < val.length; ++i) if(cpp[2*i] == 0 && cpp[2*i+1] == 0 && val.charCodeAt(i) != 0) cpp[2*i] = 0x5F; @@ -7645,7 +7645,6 @@ function parse_RString(blob, length, opts) { cell.val = str; return cell; } -/* from js-harb (C) 2014-present SheetJS */ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; var DBF = /*#__PURE__*/(function() { var dbf_codepage_map = { @@ -7894,6 +7893,7 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ { var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 }; function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { var o = opts || {}; + var old_cp = current_codepage; if(+o.codepage >= 0) set_cp(+o.codepage); if(o.type == "string") throw new Error("Cannot write DBF to JS string"); var ba = buf_array(); @@ -7956,11 +7956,17 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { h.write_shift(2, 296 + 32 * hcnt); h.write_shift(2, rlen); for(i=0; i < 4; ++i) h.write_shift(4, 0); - h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[/*::String(*/current_ansi/*::)*/] || 0x03)<<8)); + var cp = +dbf_reverse_map[/*::String(*/current_codepage/*::)*/] || 0x03; + h.write_shift(4, 0x00000000 | (cp<<8)); + if(dbf_codepage_map[cp] != +o.codepage) { + console.error("DBF Unsupported codepage " + current_codepage + ", using 1252"); + current_codepage = 1252; + } for(i = 0, j = 0; i < headers.length; ++i) { if(headers[i] == null) continue; var hf = ba.next(32); + /* TODO: test how applications handle non-ASCII field names */ var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11); hf.write_shift(1, _f, "sbcs"); hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs"); @@ -8009,6 +8015,7 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { } // data } + current_codepage = old_cp; ba.next(1).write_shift(1, 0x1A); return ba.end(); } diff --git a/xlsx.js b/xlsx.js index cfff0fb..6f89644 100644 --- a/xlsx.js +++ b/xlsx.js @@ -4011,7 +4011,7 @@ for(i = 0; i != val.length; ++i) { } size = val.length; } else if(typeof $cptable !== 'undefined' && f == 'cpstr') { - cpp = $cptable.utils.encode(current_ansi, val); + cpp = $cptable.utils.encode(current_codepage, val); /* replace null bytes with _ when relevant */ if(cpp.length == val.length) for(i = 0; i < val.length; ++i) if(cpp[i] == 0 && val.charCodeAt(i) != 0) cpp[i] = 0x5F; if(cpp.length == 2 * val.length) for(i = 0; i < val.length; ++i) if(cpp[2*i] == 0 && cpp[2*i+1] == 0 && val.charCodeAt(i) != 0) cpp[2*i] = 0x5F; @@ -7556,7 +7556,6 @@ function parse_RString(blob, length, opts) { cell.val = str; return cell; } -/* from js-harb (C) 2014-present SheetJS */ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; var DBF = (function() { var dbf_codepage_map = { @@ -7804,6 +7803,7 @@ function dbf_to_workbook(buf, opts) { var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 }; function sheet_to_dbf(ws, opts) { var o = opts || {}; + var old_cp = current_codepage; if(+o.codepage >= 0) set_cp(+o.codepage); if(o.type == "string") throw new Error("Cannot write DBF to JS string"); var ba = buf_array(); @@ -7866,11 +7866,17 @@ function sheet_to_dbf(ws, opts) { h.write_shift(2, 296 + 32 * hcnt); h.write_shift(2, rlen); for(i=0; i < 4; ++i) h.write_shift(4, 0); - h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[current_ansi] || 0x03)<<8)); + var cp = +dbf_reverse_map[current_codepage] || 0x03; + h.write_shift(4, 0x00000000 | (cp<<8)); + if(dbf_codepage_map[cp] != +o.codepage) { + console.error("DBF Unsupported codepage " + current_codepage + ", using 1252"); + current_codepage = 1252; + } for(i = 0, j = 0; i < headers.length; ++i) { if(headers[i] == null) continue; var hf = ba.next(32); + /* TODO: test how applications handle non-ASCII field names */ var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11); hf.write_shift(1, _f, "sbcs"); hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs"); @@ -7919,6 +7925,7 @@ function sheet_to_dbf(ws, opts) { } // data } + current_codepage = old_cp; ba.next(1).write_shift(1, 0x1A); return ba.end(); } diff --git a/xlsx.mjs b/xlsx.mjs index 87687aa..c529308 100644 --- a/xlsx.mjs +++ b/xlsx.mjs @@ -4086,7 +4086,7 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/ } size = val.length; } else if(typeof $cptable !== 'undefined' && f == 'cpstr') { - cpp = $cptable.utils.encode(current_ansi, val); + cpp = $cptable.utils.encode(current_codepage, val); /* replace null bytes with _ when relevant */ if(cpp.length == val.length) for(i = 0; i < val.length; ++i) if(cpp[i] == 0 && val.charCodeAt(i) != 0) cpp[i] = 0x5F; if(cpp.length == 2 * val.length) for(i = 0; i < val.length; ++i) if(cpp[2*i] == 0 && cpp[2*i+1] == 0 && val.charCodeAt(i) != 0) cpp[2*i] = 0x5F; @@ -7640,7 +7640,6 @@ function parse_RString(blob, length, opts) { cell.val = str; return cell; } -/* from js-harb (C) 2014-present SheetJS */ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; var DBF = /*#__PURE__*/(function() { var dbf_codepage_map = { @@ -7889,6 +7888,7 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ { var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 }; function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { var o = opts || {}; + var old_cp = current_codepage; if(+o.codepage >= 0) set_cp(+o.codepage); if(o.type == "string") throw new Error("Cannot write DBF to JS string"); var ba = buf_array(); @@ -7951,11 +7951,17 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { h.write_shift(2, 296 + 32 * hcnt); h.write_shift(2, rlen); for(i=0; i < 4; ++i) h.write_shift(4, 0); - h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[/*::String(*/current_ansi/*::)*/] || 0x03)<<8)); + var cp = +dbf_reverse_map[/*::String(*/current_codepage/*::)*/] || 0x03; + h.write_shift(4, 0x00000000 | (cp<<8)); + if(dbf_codepage_map[cp] != +o.codepage) { + console.error("DBF Unsupported codepage " + current_codepage + ", using 1252"); + current_codepage = 1252; + } for(i = 0, j = 0; i < headers.length; ++i) { if(headers[i] == null) continue; var hf = ba.next(32); + /* TODO: test how applications handle non-ASCII field names */ var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11); hf.write_shift(1, _f, "sbcs"); hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs"); @@ -8004,6 +8010,7 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { } // data } + current_codepage = old_cp; ba.next(1).write_shift(1, 0x1A); return ba.end(); }