UNPKG

@doodad-js/xml

Version:
2 lines 16.8 kB
// Copyright 2015-2018 Claude Petit, licensed under Apache License version 2.0 "use strict";exports.add=function add(modules){modules=(modules||{});modules['Doodad.Tools.Xml.Parsers.Libxml2']={version:'5.2.0b',dependencies:['Doodad.Tools.Xml','Doodad.Tools.Xml.Parsers.Libxml2.Loader',],create:function create(root,_options){const doodad=root.Doodad,types=doodad.Types,tools=doodad.Tools,io=doodad.IO,ioMixIns=io.MixIns,files=tools.Files,xml=tools.Xml,xmlParsers=xml.Parsers,libxml2=xmlParsers.Libxml2,libxml2Loader=libxml2.Loader;const NULL=0;const __Internal__={initialized:false,createStrPtr:null,baseDirectories:null,};__Internal__.registerBaseDirectory=function registerBaseDirectory(schemaParserCtxt,url){if(!__Internal__.baseDirectories){__Internal__.baseDirectories=tools.nullObject()};const directory=url.set({file:''});const directoryStr=directory.toApiString();if(types.has(__Internal__.baseDirectories,schemaParserCtxt)){const dirs=__Internal__.baseDirectories[schemaParserCtxt];const len=dirs.length;let found=false;for(let i=0;i<len;i++){const dir=dirs[i];if(dir[0]===directoryStr){found=true;break}};if(!found){__Internal__.baseDirectories[schemaParserCtxt].push([directoryStr,directory])}}else{__Internal__.baseDirectories[schemaParserCtxt]=[[directoryStr,directory]]}};__Internal__.unregisterBaseDirectories=function unregisterBaseDirectories(schemaParserCtxt){if(!__Internal__.baseDirectories||!types.has(__Internal__.baseDirectories,schemaParserCtxt)){throw new types.Error("Base directory not registered on schema parser '~0~'.",[schemaParserCtxt])};delete __Internal__.baseDirectories[schemaParserCtxt]};__Internal__.getBaseDirectories=function getBaseDirectories(schemaParserCtxt){if(__Internal__.baseDirectories){return types.get(__Internal__.baseDirectories,schemaParserCtxt)};return undefined};libxml2.REGISTER(types.ScriptAbortedError.$inherit({$TYPE_NAME:'AbortError',$TYPE_UUID:'68cbf932-9a3a-4649-87ec-9f5800d3261b',[types.ConstructorSymbol](what){this.what=what;return[1,"Script aborted : '~0~'.",[what]]}},{what:null,}));libxml2.ADD('init',function init(){if(__Internal__.initialized){return};const clibxml2=libxml2Loader.get();clibxml2.onExit=function onExit(status){tools.abortScript(status)};clibxml2.onAbort=function onAbort(what){throw new libxml2.AbortError(what)};clibxml2._xmlInitParser();const matchFunc=clibxml2.addFunction(function matchFunc(filenameStrPtr){return 1},'ii');const openFunc=clibxml2.addFunction(function openFunc(filenameStrPtr){return NULL},'ii');const readFunc=clibxml2.addFunction(function readFunc(inputContextPtr,bufferPtr,bufferLen){return 0},'iiii');const writeFunc=clibxml2.addFunction(function writeFunc(inputContextPtr,bufferPtr,bufferLen){return bufferLen},'iiii');const closeFunc=clibxml2.addFunction(function closeFunc(inputContextPtr){return 0},'ii');const externalLoader=clibxml2.addFunction(function externalLoader(urlStrPtr,idStrPtr,parserCtxtPtr){const url=files.parseLocation(clibxml2.Pointer_stringify(urlStrPtr));const userDataPtr=clibxml2._xmlGetUserDataFromParserCtxt(parserCtxtPtr);if(!userDataPtr){throw new types.Error("The 'libxml2' C library needs some modifications before its build.")};let content=null;if(url.isRelative){const dirs=__Internal__.getBaseDirectories(userDataPtr),len=dirs.length;for(let i=0;i<len;i++){const path=dirs[i][1].combine(url);try{content=files.readFileSync(path);__Internal__.registerBaseDirectory(userDataPtr,path);break}catch(ex){if(ex.code!=='ENOENT'){throw ex}}}}else{content=files.readFileSync(url);__Internal__.registerBaseDirectory(userDataPtr,url)};if(!content){return NULL};let contentPtr=NULL;try{const contentLen=content.length;contentPtr=clibxml2.allocate(content,'i8',clibxml2.ALLOC_NORMAL);content=null;if(!contentPtr){throw new types.Error("Failed to allocate buffer file content.")};const inputPtr=clibxml2._xmlCreateMyParserInput(parserCtxtPtr,contentPtr,contentLen);return inputPtr}catch(ex){throw ex}finally{if(contentPtr){clibxml2._free(contentPtr);contentPtr=NULL}}},'iiii');clibxml2._xmlCleanupInputCallbacks();clibxml2._xmlCleanupOutputCallbacks();clibxml2._xmlRegisterInputCallbacks(matchFunc,openFunc,readFunc,closeFunc);clibxml2._xmlRegisterOutputCallbacks(matchFunc,openFunc,writeFunc,closeFunc);clibxml2._xmlSetExternalEntityLoader(externalLoader);__Internal__.createStrPtr=function _createStrPtr(str,len){if(types.isNothing(len)){len=clibxml2.lengthBytesUTF8(str)};const ptr=clibxml2._malloc(len+1);if(ptr){clibxml2.stringToUTF8(str,ptr,len+1)};return ptr};__Internal__.initialized=true;xml.registerParser(libxml2)});libxml2.ADD('parse',function(stream,options){const Promise=types.getPromise();return Promise.try(function(){if(!__Internal__.initialized){throw new types.ParseError("'libxml2' parser must be initialized first.")};let clibxml2=null,clibxml2Cleaned=false,allocatedFunctions=null,allocatedEntities=null,sax=NULL,saxOrg=NULL,saxPtr=NULL,userPtr=NULL,userPtrOrg=NULL,userPtrPtr=NULL,urlPtr=NULL,schemaParserCtxt=NULL,schema=NULL,validCtxt=NULL,saxPlug=NULL,pushParserCtxt=NULL;let xsd=types.get(options,'xsd',null);let promise=null;if(xsd){xsd=files.parseLocation(xsd);promise=files.readFileAsync(xsd)}else{promise=Promise.resolve(null)};promise=promise.thenCreate(function libxml2ParserPromise(xsdContent,resolve,reject){root.DD_ASSERT&&root.DD_ASSERT(types._implements(stream,ioMixIns.TextInput)||types.isString(stream),"Invalid stream.");clibxml2=libxml2Loader.get();const nodoc=types.get(options,'nodoc',false),discardEntities=types.get(options,'discardEntities',false);const entities=types.get(options,'entities',null);const PTR_LEN=clibxml2._xmlPtrLen();const XML_INTERNAL_GENERAL_ENTITY=1;const XML_INTERNAL_PREDEFINED_ENTITY=6;let currentNode=null;let callback=types.get(options,'callback');if(callback){const cbObj=types.get(options,'callbackObj');callback=doodad.Callback(cbObj,callback)};const doc=(nodoc?null:new xml.Document());const getStrFromXmlCharAr=function _getStrFromXmlCharAr(ptr,index,end){if(types.isNothing(end)){return clibxml2.Pointer_stringify(clibxml2.getValue(ptr+(PTR_LEN*index),'*'))}else{const startPtr=clibxml2.getValue(ptr+(PTR_LEN*index),'*');const endPtr=clibxml2.getValue(ptr+(PTR_LEN*end),'*');return clibxml2.Pointer_stringify(startPtr,endPtr-startPtr)}};const SAX_HANDLERS={error:function error(ctxPtr,msgPtr,paramsPtr){const strPtr=clibxml2._xmlFormatGenericError(ctxPtr,msgPtr,paramsPtr);const str=clibxml2.Pointer_stringify(strPtr);if(str){tools.log(tools.LogLevels.Error,tools.trim(str,'\n'))}},warning:function warning(ctxPtr,msgPtr,paramsPtr){const strPtr=clibxml2._xmlFormatGenericError(ctxPtr,msgPtr,paramsPtr);const str=clibxml2.Pointer_stringify(strPtr);if(str&&(str.indexOf("Skipping import of schema")<0)){tools.log(tools.LogLevels.Warning,tools.trim(str,'\n'))}},getEntity:function getEntity(ctxPtr,namePtr){const name=clibxml2.Pointer_stringify(namePtr);if(name==='__proto__'){return NULL};if(!allocatedEntities){allocatedEntities=tools.nullObject()};const resolved=types.get(allocatedEntities,name);if(resolved){return allocatedEntities[name]};const entity=types.get(entities,name);if(!entity){return NULL};let newNamePtr=NULL,strPtr=NULL;try{newNamePtr=__Internal__.createStrPtr(name);if(!newNamePtr){throw new types.Error("Failed to allocate string buffer.")};strPtr=__Internal__.createStrPtr(entity);if(!strPtr){throw new types.Error("Failed to allocate string buffer.")};const entityPtr=clibxml2._xmlNewEntity(NULL,newNamePtr,(discardEntities?XML_INTERNAL_PREDEFINED_ENTITY:XML_INTERNAL_GENERAL_ENTITY),NULL,NULL,strPtr);if(!entityPtr){throw new types.Error("Failed to allocate a new entity.")};allocatedEntities[name]=entityPtr;return entityPtr}catch(ex){throw ex}finally{if(newNamePtr){clibxml2._free(newNamePtr)};if(strPtr){clibxml2._free(strPtr)}}},externalSubset:function externalSubset(ctxPtr,namePtr,externalIDPtr,systemIDPtr){const node=new xml.DocumentType(clibxml2.Pointer_stringify(namePtr));if(nodoc){callback(node)}else{doc.setDocumentType(node)}},processingInstruction:function processingInstruction(ctxPtr,targetPtr,dataPtr){const node=new xml.ProcessingInstruction(clibxml2.Pointer_stringify(targetPtr),clibxml2.Pointer_stringify(dataPtr));if(nodoc){callback(node)}else{doc.getInstructions().append(node)}},comment:function comment(ctxPtr,valuePtr){const node=new xml.Comment(clibxml2.Pointer_stringify(valuePtr));if(nodoc){callback(node)}else{currentNode.getChildren().append(node)}},startElementNs:function startElementNs(ctxPtr,localnameStrPtr,prefixStrPtr,uriStrPtr,nb_namespaces,namespacesPtrStrPtr,nb_attributes,nb_defaulted,attributesPtrStrPtr){const node=new xml.Element(clibxml2.Pointer_stringify(localnameStrPtr),clibxml2.Pointer_stringify(prefixStrPtr),clibxml2.Pointer_stringify(uriStrPtr));if(nodoc){callback(node)}else{currentNode.getChildren().append(node);currentNode=node};const attrs=(nodoc?null:currentNode.getAttrs());for(let i=0;i<nb_attributes;i++){const ptr=attributesPtrStrPtr+(PTR_LEN*5*i);const node=new xml.Attribute(getStrFromXmlCharAr(ptr,0),getStrFromXmlCharAr(ptr,3,4),getStrFromXmlCharAr(ptr,1),getStrFromXmlCharAr(ptr,2));if(nodoc){callback(node)}else{attrs.append(node)}}},characters:function characters(ctxPtr,chPtr,len){const node=new xml.Text(clibxml2.Pointer_stringify(chPtr,len));if(nodoc){callback(node)}else{currentNode.getChildren().append(node)}},cdataBlock:function cdataBlock(ctxPtr,valuePtr,len){const node=new xml.CDATASection(clibxml2.Pointer_stringify(valuePtr,len));if(nodoc){callback(node)}else{currentNode.getChildren().append(node)}},endElementNs:function endElementNs(ctxPtr,localnameStrPtr,prefixStrPtr,uriStrPtr){if(!nodoc){currentNode=currentNode.getParent()}},endDocument:function endDocument(ctxPtr){if(nodoc){callback(null)};resolve(doc);if(stream){stream.stopListening();stream=null}},};const allocFunction=function _allocFunction(name,sig){if(!allocatedFunctions){allocatedFunctions=tools.nullObject()};if(name in allocatedFunctions){return allocatedFunctions[name]};const fn=types.get(SAX_HANDLERS,name,null);let ptr=NULL;if(fn){ptr=clibxml2.addFunction(fn,sig);if(!ptr){throw new types.Error("Failed to allocate function '~0~' for the SAXHandler.",[name])};allocatedFunctions[name]=ptr};return ptr};sax=clibxml2._xmlCreateMySAXHandler(allocFunction('internalSubset','viiii'),allocFunction('isStandalone','ii'),allocFunction('hasInternalSubset','ii'),allocFunction('hasExternalSubset','ii'),allocFunction('resolveEntity','iiii'),allocFunction('getEntity','iii'),allocFunction('entityDecl','viiiiii'),allocFunction('notationDecl','viiii'),allocFunction('attributeDecl','viiiiiii'),allocFunction('elementDecl','viiii'),allocFunction('unparsedEntityDecl','viiiii'),allocFunction('setDocumentLocator','vii'),allocFunction('startDocument','vi'),allocFunction('endDocument','vi'),allocFunction('startElement','viii'),allocFunction('endElement','vii'),allocFunction('reference','vii'),allocFunction('characters','viii'),allocFunction('ignorableWhitespace','viii'),allocFunction('processingInstruction','viii'),allocFunction('comment','vii'),allocFunction('warning','viii'),allocFunction('error','viii'),allocFunction('getParameterEntity','iii'),allocFunction('cdataBlock','viii'),allocFunction('externalSubset','viiii'),allocFunction('startElementNs','viiiiiiiii'),allocFunction('endElementNs','viiii'),allocFunction('serror','vii'));if(!sax){throw new types.Error("Failed to create SAXHandler.")};saxOrg=sax;userPtr=clibxml2._malloc(4);if(!userPtr){throw new types.Error("Failed to create user context.")};userPtrOrg=userPtr;clibxml2.setValue(userPtr,0,'i32');if(xsdContent){urlPtr=__Internal__.createStrPtr(xsd.toApiString());if(!urlPtr){throw new types.Error("Failed to allocate URL string.")};schemaParserCtxt=clibxml2._xmlSchemaNewParserCtxt(urlPtr);if(!schemaParserCtxt){throw new types.Error("Failed to create schema parser.")};clibxml2._xmlSchemaSetParserErrors(schemaParserCtxt,allocFunction('error','viii'),allocFunction('warning','viii'),NULL);schema=clibxml2._xmlSchemaParse(schemaParserCtxt);if(!schema){throw new types.Error("Failed to parse schema.")};clibxml2._free(urlPtr);urlPtr=NULL;__Internal__.unregisterBaseDirectories(schemaParserCtxt);clibxml2._xmlSchemaFreeParserCtxt(schemaParserCtxt);schemaParserCtxt=NULL;validCtxt=clibxml2._xmlSchemaNewValidCtxt(schema);if(!validCtxt){throw new types.Error("Failed to create schema validator.")};saxPtr=clibxml2._malloc(PTR_LEN);if(!saxPtr){throw new types.Error("Failed to create SAX pointer.")};clibxml2.setValue(saxPtr,sax,'*');userPtrPtr=clibxml2._malloc(PTR_LEN);if(!userPtrPtr){throw new types.Error("Failed to create user context pointer.")};clibxml2.setValue(userPtrPtr,userPtr,'*');saxPlug=clibxml2._xmlSchemaSAXPlug(validCtxt,saxPtr,userPtrPtr);if(!saxPlug){throw new types.Error("Failed to plug schema with SAX.")};sax=clibxml2.getValue(saxPtr,'*');userPtr=clibxml2.getValue(userPtrPtr,'*')};if(!nodoc&&!discardEntities){tools.forEach(entities,function(value,name){const node=new xml.Entity(name,value);if(nodoc){callback(node)}else{doc.getEntities().append(node)}})};currentNode=doc;pushParserCtxt=clibxml2._xmlCreatePushParserCtxt(sax,userPtr,NULL,0,NULL);if(!pushParserCtxt){throw new types.Error("Failed to create push parser.")};if(types.isString(stream)){let valuePtr=NULL;try{const len=clibxml2.lengthBytesUTF8(stream);valuePtr=__Internal__.createStrPtr(stream,len);if(!valuePtr){throw new types.Error("Failed to allocate string buffer.")};stream=null;const res=clibxml2._xmlParseChunk(pushParserCtxt,valuePtr,len,1);if(res){throw new types.Error("Failed to parse the XML document.")};const isValid=clibxml2._xmlSchemaIsValid(validCtxt);if(isValid<=0){throw new types.Error("The XML document is invalid.")}}catch(ex){reject(ex)}finally{if(valuePtr){clibxml2._free(valuePtr);valuePtr=NULL}}}else{stream.onError.attachOnce(this,function(ev){ev.preventDefault();reject(ev.error)});stream.onReady.attach(this,function(ev){ev.preventDefault();let valuePtr=NULL;try{if(ev.data.raw===io.EOF){const res=clibxml2._xmlParseChunk(pushParserCtxt,NULL,0,1);if(res){throw new types.Error("Failed to close document.")}}else{const value=ev.data.valueOf();if(types.isString(value)){const len=clibxml2.lengthBytesUTF8(value);valuePtr=__Internal__.createStrPtr(value,len);if(!valuePtr){throw new types.Error("Failed to allocate string buffer.")};const res=clibxml2._xmlParseChunk(pushParserCtxt,valuePtr,len,0);if(res){throw new types.Error("Failed to parse chunk.")}}else{valuePtr=clibxml2.allocate(value,'i8',clibxml2.ALLOC_NORMAL);if(!valuePtr){throw new types.Error("Failed to allocate value buffer.")};const res=clibxml2._xmlParseChunk(pushParserCtxt,valuePtr,value.length,0);if(res){throw new types.Error("Failed to parse chunk.")}}};const isValid=clibxml2._xmlSchemaIsValid(validCtxt);if(isValid<=0){throw new types.Error("The XML document is invalid.")}}catch(ex){throw ex}finally{if(valuePtr){clibxml2._free(valuePtr);valuePtr=NULL}}});stream.listen()}}).nodeify(function(err,result){if(pushParserCtxt){clibxml2._xmlFreeParserCtxt(pushParserCtxt);pushParserCtxt=NULL};if(saxPlug){clibxml2._xmlSchemaSAXUnplug(saxPlug);saxPlug=NULL;userPtr=NULL};if(validCtxt){clibxml2._xmlSchemaFreeValidCtxt(validCtxt);validCtxt=NULL};if(schema){clibxml2._xmlSchemaFree(schema);schema=NULL};if(schemaParserCtxt){try{__Internal__.unregisterBaseDirectories(schemaParserCtxt)}catch(ex){};clibxml2._xmlSchemaFreeParserCtxt(schemaParserCtxt);schemaParserCtxt=NULL};if(urlPtr){clibxml2._free(urlPtr);urlPtr=NULL};if(allocatedFunctions){tools.forEach(allocatedFunctions,function(ptr,name){clibxml2.removeFunction(ptr)});allocatedFunctions=null};if(allocatedEntities){tools.forEach(allocatedEntities,function(ptr){clibxml2._xmlFreeEntity(ptr)});allocatedEntities=null};if(saxPtr){clibxml2._free(saxPtr);saxPtr=NULL};if(sax&&(sax!==saxOrg)){clibxml2._xmlFreeEx(sax);sax=NULL};if(saxOrg){clibxml2._xmlFreeMySAXHandler(saxOrg);saxOrg=NULL};if(userPtrPtr){clibxml2._free(userPtrPtr);userPtrPtr=NULL};if(userPtr&&(userPtr!==userPtrOrg)){clibxml2._xmlFreeEx(userPtr);userPtr=NULL};if(userPtrOrg){clibxml2._free(userPtrOrg);userPtrOrg=NULL};clibxml2=null;clibxml2Cleaned=true;if(err){throw err}else{return result}}).catch(function(err){if(!clibxml2Cleaned&&!types._instanceof(err,libxml2.AbortError)){throw new libxml2.AbortError(err)};throw err});return promise})});libxml2.ADD('isAvailable',function isAvailable(){return __Internal__.initialized});libxml2.ADD('hasFeatures',function hasFeatures(features){if(!__Internal__.initialized){return false};const current={schemas:(root.serverSide&&root.getOptions().debug),};return tools.every(features,function(wanted,name){return!wanted||types.get(current,name,false)})});return function init(options){const clibxml2=libxml2Loader.get();if(clibxml2){libxml2.init()}}},};return modules};