UNPKG

typesxml

Version:

Open source XML library written in TypeScript

775 lines 30.1 kB
"use strict"; /******************************************************************************* * Copyright (c) 2023 - 2024 Maxprograms. * * This program and the accompanying materials * are made available under the terms of the Eclipse License 1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-v10.html * * Contributors: * Maxprograms - initial API and implementation *******************************************************************************/ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.DTDParser = void 0; const fs_1 = require("fs"); const path = __importStar(require("node:path")); const XMLUtils_1 = require("../XMLUtils"); const Grammar_1 = require("../grammar/Grammar"); const AttListDecl_1 = require("./AttListDecl"); const ElementDecl_1 = require("./ElementDecl"); const EntityDecl_1 = require("./EntityDecl"); const NotationDecl_1 = require("./NotationDecl"); class DTDParser { grammar; catalog; pointer = 0; source; currentFile; constructor(grammar) { this.currentFile = ''; if (grammar) { this.grammar = grammar; } else { this.grammar = new Grammar_1.Grammar(); } } setCatalog(catalog) { this.catalog = catalog; } parseDTD(file) { this.parseFile(file); this.grammar.processModels(); return this.grammar; } parseFile(file) { this.source = ''; let stats = (0, fs_1.statSync)(file, { bigint: false, throwIfNoEntry: true }); this.currentFile = file; let blockSize = stats.blksize; let fileHandle = (0, fs_1.openSync)(file, 'r'); let buffer = Buffer.alloc(blockSize); let bytesRead = (0, fs_1.readSync)(fileHandle, buffer, 0, blockSize, 0); while (bytesRead > 0) { this.source += buffer.toString('utf8', 0, bytesRead); bytesRead = (0, fs_1.readSync)(fileHandle, buffer, 0, blockSize, this.source.length); } (0, fs_1.closeSync)(fileHandle); return this.parse(); } parseString(source) { this.source = source; this.parse(); this.grammar.processModels(); return this.grammar; } parse() { this.pointer = 0; while (this.pointer < this.source.length) { if (this.lookingAt('<!ELEMENT')) { let index = this.source.indexOf('>', this.pointer); if (index === -1) { throw new Error('Malformed element declaration'); } let elementText = this.source.substring(this.pointer, index + '>'.length); let length = elementText.length; let elementDecl = this.parseElementDeclaration(elementText); this.grammar.addElement(elementDecl); this.pointer += length; continue; } if (this.lookingAt('<!ATTLIST')) { let index = this.source.indexOf('>', this.pointer); if (index === -1) { throw new Error('Malformed attribute declaration'); } let attListText = this.source.substring(this.pointer, index + '>'.length); let length = attListText.length; let attList = this.parseAttributesListDeclaration(attListText); this.grammar.addAttributes(attList.getName(), attList.getAttributes()); this.pointer += length; continue; } if (this.lookingAt('<!ENTITY')) { let index = this.source.indexOf('>', this.pointer); if (index === -1) { throw new Error('Malformed entity declaration'); } let entityDeclText = this.source.substring(this.pointer, index + '>'.length); let entityDecl = this.parseEntityDeclaration(entityDeclText); this.grammar.addEntity(entityDecl); this.pointer += entityDeclText.length; continue; } if (this.lookingAt('<!NOTATION')) { let index = this.source.indexOf('>', this.pointer); if (index === -1) { throw new Error('Malformed notation declaration'); } let notationDeclText = this.source.substring(this.pointer, index + '>'.length); if (XMLUtils_1.XMLUtils.hasParameterEntity(notationDeclText)) { notationDeclText = this.resolveEntities(notationDeclText); } let notation = this.parseNotationDeclaration(notationDeclText); this.grammar.addNotation(notation); this.pointer += notationDeclText.length; continue; } if (this.lookingAt('<![')) { this.parseConditionalSection(); continue; } if (this.lookingAt(']]>')) { this.endConditionalSection(); continue; } if (this.lookingAt('<?')) { let index = this.source.indexOf('?>', this.pointer); if (index === -1) { throw new Error('Malformed processing instruction'); } // skip processing instructions this.pointer = index + '?>'.length; continue; } if (this.lookingAt('<!--')) { let index = this.source.indexOf('-->', this.pointer); if (index === -1) { throw new Error('Malformed comment'); } // skip comments this.pointer = index + '-->'.length; continue; } if (this.lookingAt('%')) { let index = this.source.indexOf(';', this.pointer); if (index == -1) { throw new Error('Malformed entity reference'); } let entityName = this.source.substring(this.pointer + '%'.length, index); let entity = this.grammar.getEntity(entityName); if (entity === undefined) { throw new Error('Unknown entity: ' + entityName); } let value = entity.getValue(); if (value !== '') { let start = this.source.substring(0, this.pointer); let end = this.source.substring(index + ';'.length); this.source = start + value + end; this.pointer += value.length; } else if (entity.getSystemId() !== '' || entity.getPublicId() !== '') { let location = this.resolveEntity(entity.getPublicId(), entity.getSystemId()); let parser = new DTDParser(this.grammar); parser.setCatalog(this.catalog); let externalGrammar = parser.parseFile(location); this.grammar.merge(externalGrammar); this.pointer = index + ';'.length; } else { // empty entity, ignore this.pointer = index + ';'.length; } continue; } let char = this.source.charAt(this.pointer); if (XMLUtils_1.XMLUtils.isXmlSpace(char)) { this.pointer++; continue; } throw new Error('Error parsing ' + this.currentFile + ' at ' + this.source.substring(this.pointer - 10, this.pointer) + ' @ ' + this.source.substring(this.pointer, this.pointer + 30)); } return this.grammar; } endConditionalSection() { // jump over ]]> this.pointer += ']]>'.length; } parseConditionalSection() { this.pointer += '<!['.length; // skip spaces before section keyword for (; this.pointer < this.source.length; this.pointer++) { let char = this.source.charAt(this.pointer); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } // read section keyword let keyword = ''; for (; this.pointer < this.source.length; this.pointer++) { let char = this.source.charAt(this.pointer); if (XMLUtils_1.XMLUtils.isXmlSpace(char) || char === '[') { break; } keyword += char; } if (XMLUtils_1.XMLUtils.hasParameterEntity(keyword)) { keyword = this.resolveEntities(keyword); } if ('INCLUDE' === keyword) { // jump to the start of the content for (; this.pointer < this.source.length; this.pointer++) { let char = this.source.charAt(this.pointer); if (char === '[') { break; } } this.pointer++; } else if ('IGNORE' === keyword) { this.skipIgnoreSection(); } else { throw new Error('Malformed conditional section'); } } skipIgnoreSection() { let stack = 1; while (this.pointer < this.source.length) { if (this.lookingAt('<![')) { stack++; this.pointer += '<!['.length; } else if (this.lookingAt(']]>')) { stack--; this.pointer += ']]>'.length; if (stack === 0) { return; } } else { this.pointer++; } } } resolveEntities(fragment) { while (XMLUtils_1.XMLUtils.hasParameterEntity(fragment)) { let start = fragment.indexOf('%'); let end = fragment.indexOf(';'); let entityName = fragment.substring(start + '%'.length, end); let entity = this.grammar.getEntity(entityName); if (entity === undefined) { throw new Error('Unknown entity: ' + entityName); } fragment = fragment.replace('%' + entityName + ';', entity.getValue()); } return fragment; } parseEntityDeclaration(declaration) { let name = ''; let i = '<!ENTITY'.length; let char = declaration.charAt(i); // skip spaces before % or entity name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let parameterEntity = false; if (char === '%') { parameterEntity = true; // skip spaces before name i++; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } } // get entity name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } name += char; } if (XMLUtils_1.XMLUtils.hasParameterEntity(name)) { name = this.resolveEntities(name); } // skip spaces before entity value or external id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } if (parameterEntity) { // can have value or external id if (XMLUtils_1.XMLUtils.lookingAt('PUBLIC', declaration, i)) { i += 'PUBLIC'.length; // skip spaces before public id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let separator = declaration.charAt(i); i++; // skip opening " // get public id let publicId = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } publicId += char; } i++; // skip closing " if (XMLUtils_1.XMLUtils.hasParameterEntity(publicId)) { publicId = this.resolveEntities(publicId); } // skip spaces before system id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } separator = declaration.charAt(i); i++; // skip opening " // get system id let systemId = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } systemId += char; } if (XMLUtils_1.XMLUtils.hasParameterEntity(systemId)) { systemId = this.resolveEntities(systemId); } return new EntityDecl_1.EntityDecl(name, parameterEntity, '', systemId, publicId, ''); } else if (XMLUtils_1.XMLUtils.lookingAt('SYSTEM', declaration, i)) { // skip spaces before system id i += 'SYSTEM'.length; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let separator = declaration.charAt(i); i++; // skip opening " // get system id let systemId = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } systemId += char; } if (XMLUtils_1.XMLUtils.hasParameterEntity(systemId)) { systemId = this.resolveEntities(systemId); } return new EntityDecl_1.EntityDecl(name, parameterEntity, '', systemId, '', ''); } else { // get entity value let separator = declaration.charAt(i); i++; // skip opening " let value = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } value += char; } return new EntityDecl_1.EntityDecl(name, parameterEntity, value, '', '', ''); } } else { // Not a parameterEntity. Similar, but may declare NDATA if (XMLUtils_1.XMLUtils.lookingAt('PUBLIC', declaration, i)) { i += 'PUBLIC'.length; // skip spaces before public id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let separator = declaration.charAt(i); i++; // skip " // get public id let publicId = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } publicId += char; } i++; // skip closing " if (XMLUtils_1.XMLUtils.hasParameterEntity(publicId)) { publicId = this.resolveEntities(publicId); } // skip spaces before system id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } separator = declaration.charAt(i); i++; // skip " // get system id let systemId = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } systemId += char; } i++; // skip closing " if (XMLUtils_1.XMLUtils.hasParameterEntity(systemId)) { systemId = this.resolveEntities(systemId); } // skip spaces before NDATA for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } if (XMLUtils_1.XMLUtils.lookingAt('NDATA', declaration, i)) { i += 'NDATA'.length; // skip spaces before ndata name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } // get ndata name let ndata = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } ndata += char; } if (XMLUtils_1.XMLUtils.hasParameterEntity(ndata)) { ndata = this.resolveEntities(ndata); } return new EntityDecl_1.EntityDecl(name, parameterEntity, '', systemId, publicId, ndata); } return new EntityDecl_1.EntityDecl(name, parameterEntity, '', systemId, publicId, ''); } else if (XMLUtils_1.XMLUtils.lookingAt('SYSTEM', declaration, i)) { i += 'SYSTEM'.length; // skip spaces before system id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let separator = declaration.charAt(i); i++; // skip " // get system id let systemId = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } systemId += char; } if (XMLUtils_1.XMLUtils.hasParameterEntity(systemId)) { systemId = this.resolveEntities(systemId); } // skip spaces before NDATA for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } if (XMLUtils_1.XMLUtils.lookingAt('NDATA', declaration, i)) { i += 'NDATA'.length; // skip spaces before ndata name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } // get ndata name let ndata = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } ndata += char; } if (XMLUtils_1.XMLUtils.hasParameterEntity(ndata)) { ndata = this.resolveEntities(ndata); } return new EntityDecl_1.EntityDecl(name, parameterEntity, '', systemId, '', ndata); } return new EntityDecl_1.EntityDecl(name, parameterEntity, '', systemId, '', ''); } else { // get entity value let separator = declaration.charAt(i); i++; // skip " let value = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } value += char; } return new EntityDecl_1.EntityDecl(name, parameterEntity, value, '', '', ''); } } } parseNotationDeclaration(declaration) { let name = ''; let i = '<!NOTATION'.length; let char = declaration.charAt(i); // skip spaces before notation name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } // get notation name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } name += char; } // skip spaces before external id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let publicId = ''; let systemId = ''; if (XMLUtils_1.XMLUtils.lookingAt('PUBLIC', declaration, i)) { i += 'PUBLIC'.length; // skip spaces before public id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let separator = declaration.charAt(i); i++; // skip opening " // get public id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } publicId += char; } i++; // skip closing " if (XMLUtils_1.XMLUtils.hasParameterEntity(publicId)) { publicId = this.resolveEntities(publicId); } // skip spaces before system id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } separator = declaration.charAt(i); i++; // skip opening " // get system id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } systemId += char; } } else if (XMLUtils_1.XMLUtils.lookingAt('SYSTEM', declaration, i)) { i += 'SYSTEM'.length; // skip spaces before system id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let separator = declaration.charAt(i); i++; // skip opening " // get system id for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === separator) { break; } systemId += char; } } else { throw new Error('Malformed notation declaration'); } return new NotationDecl_1.NotationDecl(name, publicId, systemId); } parseAttributesListDeclaration(declaration) { let i = '<!ATTLIST'.length; let char = declaration.charAt(i); // skip spaces before list name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } // get list name let name = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } name += char; } // skip spaces before attributes declaration for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } let attributesText = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === '>') { break; } attributesText += char; } let list = new AttListDecl_1.AttListDecl(name, attributesText); return list; } parseElementDeclaration(declaration) { let name = ''; let i = '<!ELEMENT'.length; let char = declaration.charAt(i); // skip spaces before element name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } // get element name for (; i < declaration.length; i++) { char = declaration.charAt(i); if (XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } name += char; } // skip spaces before content spec for (; i < declaration.length; i++) { char = declaration.charAt(i); if (!XMLUtils_1.XMLUtils.isXmlSpace(char)) { break; } } // get content spec let contentSpec = ''; for (; i < declaration.length; i++) { char = declaration.charAt(i); if (char === '>') { break; } contentSpec += char; } return new ElementDecl_1.ElementDecl(name, contentSpec); } lookingAt(text) { let length = text.length; if (this.pointer + length > this.source.length) { return false; } for (let i = 0; i < length; i++) { if (this.source[this.pointer + i] !== text[i]) { return false; } } return true; } resolveEntity(publicId, systemId) { let location = this.catalog.resolveEntity(publicId, systemId); if (!location && systemId !== '' && !systemId.startsWith('http')) { location = this.makeAbsolute(systemId); } if (location) { return location; } if (systemId.startsWith('http')) { return systemId; } throw new Error('Entity not found: "' + publicId + '" "' + systemId + '"'); } makeAbsolute(uri) { let currentPath = path.dirname(this.currentFile); return currentPath + path.sep + uri; } getGrammar() { return this.grammar; } } exports.DTDParser = DTDParser; //# sourceMappingURL=DTDParser.js.map