2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
12 * The Original Code is the Sablotron XSLT Processor.
14 * The Initial Developer of the Original Code is Ginger Alliance Ltd.
15 * Portions created by Ginger Alliance are Copyright (C) 2000-2002
16 * Ginger Alliance Ltd. All Rights Reserved.
20 * Alternatively, the contents of this file may be used under the
21 * terms of the GNU General Public License Version 2 or later (the
22 * "GPL"), in which case the provisions of the GPL are applicable
23 * instead of those above. If you wish to allow use of your
24 * version of this file only under the terms of the GPL and not to
25 * allow others to use your version of this file under the MPL,
26 * indicate your decision by deleting the provisions above and
27 * replace them with the notice and other provisions required by
28 * the GPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under either the MPL or the
33 /****************************************
37 ****************************************/
39 // #include<iostream.h>
45 #define SablotAsExport
58 #include "domprovider.h"
64 #define P( PTR ) ((Processor *)(PTR))
65 #define EE(statement) {int code___=(statement); if (code___) return code___;}
66 #define ES(statement) {if (statement) return SIT(S).getError();}
67 // same as EE() but destroys the given processor
68 #define EE_D(CODE,PROC) {int code___=(CODE); if (code___) {SablotDestroyProcessor(PROC); return code___;}}
69 // error-checking chain
70 #define EC( VAR, STMT ) {if (!VAR) VAR = STMT;}
71 #define SIT( S ) (*(Situation*)S)
74 /****************************************
76 ****************************************/
77 #define checkErr(situation) {if (situation->isError()) \
78 {Warn(situation, W_PENDING_ERROR); return NOT_OK;}}
81 /****************************************
83 ****************************************/
87 S.message(MT_LOG, L_START, S.timeStr(), (char*) NULL);
88 // Log1(S, L_START, S.timeStr());
93 S.message(MT_LOG, L_STOP, S.timeStr(), (char*) NULL);
94 // Log1(S, L_STOP, S.timeStr());
98 S.message(MT_ERROR, e,(char*) NULL, (char*)NULL); \
103 // report function to enable the Sablot... globals to use Err and Log
104 void report(Sit S, MsgType type, MsgCode code, const Str& arg1, const Str& arg2)
106 S.message(type, code, arg1, arg2);
112 // situation functions
116 int SablotCreateSituation(SablotSituation *sPtr)
118 *sPtr = new Situation;
124 int SablotDestroySituation(SablotSituation S)
126 if (S) delete (Situation*)S;
131 int SablotSetOptions(SablotSituation S, int flags)
133 ((Situation*)S) -> setFlags(flags);
137 int SablotGetOptions(SablotSituation S)
139 return ((Situation*)S) -> getFlags();
142 int SablotClearSituation(SablotSituation S)
144 ((Situation*)S) -> clear();
149 // document functions
152 int SablotCreateDocument(SablotSituation S, SDOM_Document *D)
154 // non-XSL tree with empty name
155 Tree *t = new Tree((char*)"", FALSE);
156 SabArena &ar = t -> getArena();
157 NmSpace *nm = new (&ar) NmSpace(*t, t -> unexpand("xml"),
158 t -> unexpand(theXMLNamespace),
159 TRUE, NSKIND_DECLARED);
160 RootNode &root = t -> getRoot();
161 root.namespaces.append(nm);
177 double time_was = getMillisecs();
181 // make absolute address
182 char *parserBase = NULL;
186 base = Str("file://") + base;
187 // should call Processor::findBaseURI() here (but have no Processor)
188 makeAbsoluteURI(SIT(S), uri, base, absolute);
189 parserBase = (char*)absolute;
192 absolute = "arg:/_parsed_";
194 // create the tree and dataline
196 GP( Tree ) newTree = new Tree(absolute, /* isXSL = */ asStylesheet);
197 TreeConstructer tc(SIT(S));
199 // add buffer if there is one
201 argList.appendConstruct("/_parsed_", buffer);
204 EC( code, line.open(SIT(S), absolute, DLMODE_READ, &argList) );
206 Log1(SIT(S), L1_PARSING, absolute);
207 EC( code, tc.parseDataLineUsingExpat(SIT(S), newTree, &line, parserBase) );
208 EC( code, line.close(SIT(S)) );
209 *D = &(newTree.keep() -> getRoot());
210 Log1(SIT(S), L1_PARSE_DONE, getMillisecsDiff(time_was));
212 argList.freeall(FALSE);
213 return SIT(S).getError();
222 return SablotParse_(S, uri, NULL, D, FALSE);
225 int SablotParseBuffer(
230 return SablotParse_(S, NULL, buffer, D, FALSE);
233 int SablotParseStylesheet(
238 return SablotParse_(S, uri, NULL, D, TRUE);
241 int SablotParseStylesheetBuffer(
246 return SablotParse_(S, NULL, buffer, D, TRUE);
249 int SablotLockDocument(SablotSituation S, SDOM_Document D)
251 ((RootNode*)D) -> getOwner().makeStamps();
255 int SablotDestroyDocument(SablotSituation S, SDOM_Document D)
257 delete &((toRoot(toV(D))) -> getOwner());
264 // SablotCreateProcessor
268 int SablotCreateProcessor(void **processorPtr)
270 // to debug memory leaks in MSVC, uncomment the call to checkLeak()
271 // and set _crtBreakAlloc to the # of block (proc=51)
273 // create a new situation for this processor
275 SablotCreateSituation(&newSit);
277 #if defined(HAVE_MTRACE) && defined(CHECK_LEAKS)
280 *processorPtr = new Processor;
283 ((Situation*)newSit) -> message(MT_ERROR, E_MEMORY, (char*) NULL, (char*) NULL);
285 // Err( *newSit, E_MEMORY );
287 // the processor must remember its situation (this is just to
288 // avoid compatibility breakdown)
289 P( *processorPtr ) -> rememberSituation((Situation*)newSit);
290 SIT( newSit).setProcessor( P(*processorPtr) );
292 // the following seems superfluous - the processor is new
293 // checkErr( P(*processorPtr)->situation );
294 doStart ( SIT( newSit ) );
298 int SablotCreateProcessorForSituation(SablotSituation S, void **processorPtr)
300 #if defined(HAVE_MTRACE) && defined(CHECK_LEAKS)
303 *processorPtr = new Processor;
306 SIT(S).message(MT_ERROR, E_MEMORY, (char*) NULL, (char*) NULL);
309 P( *processorPtr ) -> rememberMasterSituation((Situation*)S);
310 SIT(S).setProcessor( P(*processorPtr) ); // this will go asap
318 const char *paramName,
319 const char *paramValue)
322 ES( P(processor_) -> addGlobalParam(SIT(S),
323 (char*)paramName, (char*)paramValue) );
327 int SablotAddArgBuffer(
331 const char *bufferValue)
334 if (!(P(processor_) -> getAddedFlag()))
335 SablotFreeResultArgs (processor_);
336 ES( P(processor_) -> useArg(SIT(S), (char*)argName, (char*)bufferValue) );
340 int SablotAddArgTree(
347 if (!(P(processor_) -> getAddedFlag()))
348 SablotFreeResultArgs (processor_);
349 ES( P(processor_) -> useTree(SIT(S), (char*) argName,
350 &(toRoot(tree) -> getOwner())) );
354 int SablotRunProcessorGen(
357 const char *sheetURI,
358 const char *inputURI,
359 const char *resultURI)
363 void *saveproc = processor_;
364 SIT(S).swapProcessor(saveproc);
367 // remove the existing 'arg' buffers
368 if (!(P(processor_) -> getAddedFlag()))
369 EC( code, SablotFreeResultArgs (processor_) );
371 P(processor_) -> prepareForRun();
372 // must first open the files, then use global params
373 // because VarsList needs stylesheet's dictionary
374 EC( code, P(processor_) -> open(SIT(S), sheetURI,inputURI) );
375 EC( code, P(processor_) -> useGlobalParams(SIT(S)) );
376 EC( code, P(processor_) -> run(SIT(S), resultURI) );
377 code = SIT(S).getError();
378 P(processor_) -> cleanupAfterRun((Situation*)S);
381 // GP: if not all files could be opened, those that could are
382 // closed in cleanupAfterRun
383 // code = SIT(S).getError();
384 P(processor_) -> freeResultArgs(SIT(S));
387 SIT(S).swapProcessor(saveproc);
391 int SablotRunProcessorExt(
394 const char *sheetURI,
395 const char *resultURI,
400 doc = SXP_MASK_LEVEL(doc, SIT(S).getSXPMaskBit());
402 void *saveproc = processor_;
403 SIT(S).swapProcessor(saveproc);
406 // remove the existing 'arg' buffers
407 if (!(P(processor_) -> getAddedFlag()))
408 EC( code, SablotFreeResultArgs (processor_) );
410 P(processor_) -> prepareForRun();
411 // must first open the files, then use global params
412 // because VarsList needs stylesheet's dictionary
413 EC( code, P(processor_) -> open(SIT(S), sheetURI, NULL) );
414 EC( code, P(processor_) -> useGlobalParams(SIT(S)) );
415 EC( code, P(processor_) -> run(SIT(S), resultURI, doc) );
416 code = SIT(S).getError();
417 P(processor_) -> cleanupAfterRun((Situation*)S);
420 // GP: if not all files could be opened, those that could are
421 // closed in cleanupAfterRun
422 // code = SIT(S).getError();
423 P(processor_) -> freeResultArgs(SIT(S));
426 SIT(S).swapProcessor(saveproc);
433 // SablotRunProcessor
436 int SablotRunProcessor(void *processor_,
437 const char *sheetURI,
438 const char *inputURI,
439 const char *resultURI,
441 const char **arguments)
443 Bool problem = FALSE;
444 Sit S = *(NZ(P( processor_ )) -> recallSituation());
447 // remove the existing 'arg' buffers
449 E( SablotFreeResultArgs (processor_));
450 P(processor_) -> prepareForRun();
454 for (p = arguments; *p && !problem; p += 2)
455 problem = P(processor_) -> useArg(S, p[0], p[1]);
459 // must first open the files, then use global params
460 // because VarsList needs stylesheet's dictionary
461 problem = P(processor_) -> open(S, sheetURI,inputURI);
464 for (p = params; *p && !problem; p += 2)
465 problem = P(processor_) -> useGlobalParam(S, p[0], p[1]);
468 if (problem || P(processor_) -> run(S, resultURI))
470 // GP: if not all files could be opened, those that could are
471 // closed in cleanupAfterRun
472 int code = S.getError();
473 P(processor_) -> cleanupAfterRun(&S);
474 P(processor_) -> freeResultArgs(S);
476 // S.clear(); (why forget the message?)
480 P(processor_) -> cleanupAfterRun(&S);
488 // SablotDestroyProcessor
493 int SablotDestroyProcessor(void *processor_)
496 Bool killSit = !(P( processor_ ) -> situationIsMaster());
497 Situation *SP = P(processor_) -> recallSituation();
498 code = SablotFreeResultArgs(processor_);
500 if(processor_) delete P( processor_);
504 #if defined(WIN32) && defined(CHECK_LEAKS)
519 int SablotSetBase(void* processor_,
522 P(processor_) -> setHardBaseURI(theBase);
529 // SablotSetBaseForScheme
533 int SablotSetBaseForScheme(void* processor_,
534 const char *scheme, const char *base)
536 P(processor_) -> addBaseURIMapping(scheme, base);
545 // SablotGetResultArg
549 int SablotGetResultArg(void *processor_,
553 char *newCopy; // GP: OK
554 // we even obtain the index of the output buffer but won't use it
558 Situation *s = P(processor_) -> recallSituation();
559 assert(s); //we always should have some situation, master or internal
560 P(processor_) -> copyArg(SIT(s), argURI, &resultNdx_, newCopy);
561 // if output does not go to a buffer, newCopy is NULL
574 int SablotSetLog(void *processor_,
575 const char *logFilename, int logLevel)
577 P(processor_) -> recallSituation()->msgOutputFile((char *)"stderr",(char*) logFilename);
578 // logLevel ignored so far
583 /*****************************************************************
586 the main function published by Sablotron. Feeds given XML
587 input to a stylesheet. Both of these as well as the location for
588 output are identified by a URI. One can also pass top-level
589 stylesheet parameters and named buffers ('args').
591 sheetURI URI of the XSLT stylesheet
592 inputURI URI of the XML document
593 resultURI URI of the output document
594 params a NULL-terminated array of char*'s defining the top-level
595 parameters to be passed, interpreted as a
596 sequence of (name, value) pairs.
597 arguments a NULL-terminated array of char*'s defining the named
598 buffers to be passed, interpreted as a
599 sequence of (name, value) pairs. Both params and arguments
603 resultArg in case output goes to a named buffer, *resultArg is set to
604 point to it (otherwise to NULL). Free it using SablotFree().
605 *****************************************************************/
607 int SablotProcess(const char *sheetURI, const char *inputURI,
608 const char *resultURI,
609 const char **params, const char **arguments,
613 EE( SablotCreateProcessor (&theproc) );
614 EE_D( SablotRunProcessor(theproc,
615 sheetURI, inputURI, resultURI,
616 params, arguments), theproc );
617 EE_D( SablotGetResultArg(theproc, resultURI, resultArg), theproc );
618 EE( SablotDestroyProcessor(theproc) );
623 /*****************************************************************
626 calls SablotProcess to process files identified by their
627 file names. No named buffers or params are passed. Included
628 for backward compatibility.
630 styleSheetName, inputName, resultName
631 file names of the stylesheet, XML input and output,
635 *****************************************************************/
638 int SablotProcessFiles(const char *styleSheetName,
639 const char *inputName,
640 const char *resultName)
642 return SablotProcess(
643 styleSheetName, inputName, resultName,
648 /*****************************************************************
651 calls SablotProcess to process documents in memory, passing
652 pointers to the documents. No named buffers or params are passed.
653 Included for backward compatibility.
655 styleSheetStr, inputStr
656 text of the stylesheet and the XML input
659 *resultStr pointer to the newly allocated block containing
661 *****************************************************************/
662 int SablotProcessStrings(const char *styleSheetStr,
663 const char *inputStr,
666 const char *argums[] =
668 "/_stylesheet", styleSheetStr,
669 "/_xmlinput", inputStr,
670 "/_output", NULL, //was: *resultStr,
673 return SablotProcess("arg:/_stylesheet",
676 NULL, argums, resultStr);
680 /*****************************************************************
681 SablotProcessStringsWithBase
683 Like SablotProcessStrings but lets you pass an URI that replaces
684 the stylesheet's URI in relative address resolution.
687 styleSheetStr, inputStr
688 text of the stylesheet and the XML input
689 theHardBase the "hard base URI" replacing the stylesheet's URI
690 in all relevant situations
693 *resultStr pointer to the newly allocated block containing
695 *****************************************************************/
697 int SablotProcessStringsWithBase(const char *styleSheetStr,
698 const char *inputStr,
700 const char *theHardBase)
702 const char *argums[] =
704 "/_stylesheet", styleSheetStr,
705 "/_xmlinput", inputStr,
706 "/_output", NULL, //was: *resultStr,
710 EE( SablotCreateProcessor(&theproc));
711 EE_D( SablotSetBase(theproc, theHardBase), theproc );
712 EE_D( SablotRunProcessor(theproc,
716 NULL, argums), theproc);
717 EE_D( SablotGetResultArg(theproc,
718 "arg:/_output", resultStr), theproc);
719 EE( SablotDestroyProcessor(theproc));
724 /*****************************************************************
727 Frees the Sablotron-allocated buffer.
728 *****************************************************************/
730 int SablotFree(char *resultStr)
740 // SablotFreeResultArgs
741 // frees the result arg buffers after the have been obtained
742 // via SablotGetResultArg()
746 int SablotFreeResultArgs(void *processor_)
748 EE( P(processor_) -> freeResultArgs(*(P(processor_) -> recallSituation())) );
759 int SablotRegHandler(void *processor_,
760 /* HLR_MESSAGE, HLR_SCHEME, HLR_SAX, HLR_MISC */
765 Sit S = *(P(processor_) -> recallSituation());
766 EE( P(processor_) -> setHandler(S, type, handler, userData) );
767 if (type == HLR_MESSAGE)
768 EE( S.closeFiles() );
776 // SablotUnregHandler
780 int SablotUnregHandler(void *processor_,
781 HandlerType type, /* HLR_MESSAGE, HLR_SCHEME, HLR_SAX */
785 Sit S = *(P(processor_) -> recallSituation());
786 EE( P(processor_) -> setHandler(S, type, NULL, NULL) );
787 if (type == HLR_MESSAGE)
788 EE( S.openDefaultFiles() );
799 const char* SablotGetMsgText(int code)
801 return GetMessage((MsgCode) code) -> text;
810 int SablotClearError(void *processor_)
812 P(processor_) -> recallSituation() -> clear();
818 // SablotSetInstanceData
822 void SablotSetInstanceData(void *processor_, void *idata)
824 P(processor_) -> setInstanceData(idata);
829 // SablotGetInstanceData
833 void* SablotGetInstanceData(void *processor_)
835 return P(processor_) -> getInstanceData();
841 // sets the output encoding to be used regardless of the encoding
842 // specified by the stylesheet
843 // To unset, call with encoding_ NULL.
847 void SablotSetEncoding(void *processor_, char *encoding_)
849 P(processor_) -> setHardEncoding(
850 encoding_ ? encoding_ : (const char*) "");