From e1032d9e6a7f94fe0d1c8a628139a92acaf81bc7 Mon Sep 17 00:00:00 2001 From: agerasimov Date: Thu, 19 Sep 2024 21:39:19 +0300 Subject: [PATCH] PR #386: Use `Buffer` instead of string concatenation for huge XML support. --- src/main.ts | 6 +++--- src/xml.ts | 27 +++++++++++++++++++++------ src/zip.ts | 6 +++--- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main.ts b/src/main.ts index c47d813a..d7eee18d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -222,7 +222,7 @@ async function createReport( logger.debug('Converting report to XML...'); const reportXml = buildXml(report1, xmlOptions); - if (_probe === 'XML') return reportXml; + if (_probe === 'XML') return reportXml.toString('utf-8'); logger.debug('Writing report...'); zipSetText(zip, `${TEMPLATE_PATH}/${mainDocument}`, reportXml); @@ -478,7 +478,7 @@ const processImages = async ( logger.debug(`Writing image ${imageId} (${imgName})...`); const imgPath = `${TEMPLATE_PATH}/media/${imgName}`; if (typeof imgData === 'string') { - zipSetBase64(zip, imgPath, imgData); + zipSetBase64(zip, imgPath, Buffer.from(imgData)); } else { zipSetBinary(zip, imgPath, imgData); } @@ -550,7 +550,7 @@ const processHtmls = async ( logger.debug(`Writing html ${htmlId} (${htmlName})...`); const htmlPath = `${TEMPLATE_PATH}/${htmlName}`; htmlFiles.push(`/${htmlPath}`); - zipSetText(zip, htmlPath, htmlData); + zipSetText(zip, htmlPath, Buffer.from(htmlData)); addChild( rels, newNonTextNode('Relationship', { diff --git a/src/xml.ts b/src/xml.ts index 2ba108be..ad7dfb69 100755 --- a/src/xml.ts +++ b/src/xml.ts @@ -54,10 +54,16 @@ type XmlOptions = { }; const buildXml = (node: Node, options: XmlOptions, indent: string = '') => { - let xml = indent.length + const xml = indent.length ? '' : ''; - if (node._fTextNode) xml += sanitizeText(node._text, options); + + let xmlBuffer = Buffer.from(xml, 'utf-8'); + if (node._fTextNode) + xmlBuffer = Buffer.concat([ + xmlBuffer, + Buffer.from(sanitizeText(node._text, options)), + ]); else { let attrs = ''; const nodeAttrs = node._attrs; @@ -66,18 +72,27 @@ const buildXml = (node: Node, options: XmlOptions, indent: string = '') => { }); const fHasChildren = node._children.length > 0; const suffix = fHasChildren ? '' : '/'; - xml += `\n${indent}<${node._tag}${attrs}${suffix}>`; + xmlBuffer = Buffer.concat([ + xmlBuffer, + Buffer.from(`\n${indent}<${node._tag}${attrs}${suffix}>`), + ]); let fLastChildIsNode = false; node._children.forEach(child => { - xml += buildXml(child, options, `${indent} `); + xmlBuffer = Buffer.concat([ + xmlBuffer, + buildXml(child, options, `${indent} `), + ]); fLastChildIsNode = !child._fTextNode; }); if (fHasChildren) { const indent2 = fLastChildIsNode ? `\n${indent}` : ''; - xml += `${indent2}`; + xmlBuffer = Buffer.concat([ + xmlBuffer, + Buffer.from(`${indent2}`), + ]); } } - return xml; + return xmlBuffer; }; const sanitizeText = (str: string, options: XmlOptions) => { diff --git a/src/zip.ts b/src/zip.ts index 3415f55c..5baae889 100644 --- a/src/zip.ts +++ b/src/zip.ts @@ -7,11 +7,11 @@ const zipGetText = (zip: JSZip, filename: string) => { return file_in_zip.async('text'); }; -const zipSetText = (zip: JSZip, filename: string, data: string) => - zip.file(filename, data); +const zipSetText = (zip: JSZip, filename: string, data: Buffer) => + zip.file(filename, data, { binary: false }); const zipSetBinary = (zip: JSZip, filename: string, data: ArrayBuffer) => zip.file(filename, data, { binary: true }); -const zipSetBase64 = (zip: JSZip, filename: string, data: string) => +const zipSetBase64 = (zip: JSZip, filename: string, data: Buffer) => zip.file(filename, data, { base64: true }); const zipSave = (zip: JSZip) => zip.generateAsync({