1 /* xmlj_sax.c -
2    Copyright (C) 2004 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 #include "xmlj_sax.h"
39 #include "xmlj_io.h"
40 #include "xmlj_util.h"
41 #include <unistd.h>
42 #include <string.h>
43 
44 xmlExternalEntityLoader defaultLoader = NULL;
45 
46 void
47 xmljDispatchError (xmlParserCtxtPtr ctx,
48                    xmlSAXLocatorPtr loc,
49                    JNIEnv *env,
50                    jobject target,
51                    jmethodID method,
52                    const char *msg,
53                    va_list args);
54 
55 /* -- GnomeLocator -- */
56 
57 JNIEXPORT jstring JNICALL
Java_gnu_xml_libxmlj_sax_GnomeLocator_publicId(JNIEnv * env,jobject self,jobject j_ctx,jobject j_loc)58 Java_gnu_xml_libxmlj_sax_GnomeLocator_publicId (JNIEnv * env,
59                                                 jobject self
60 						__attribute__((__unused__)),
61                                                 jobject j_ctx,
62                                                 jobject j_loc)
63 {
64   xmlParserCtxtPtr ctx;
65   xmlSAXLocatorPtr loc;
66   SAXParseContext *sax;
67 
68   ctx = (xmlParserCtxtPtr) xmljAsPointer (env, j_ctx);
69   loc = (xmlSAXLocatorPtr) xmljAsPointer (env, j_loc);
70   sax = (SAXParseContext *) ctx->_private;
71 
72   return sax->publicId;
73 }
74 
75 JNIEXPORT jstring JNICALL
Java_gnu_xml_libxmlj_sax_GnomeLocator_systemId(JNIEnv * env,jobject self,jobject j_ctx,jobject j_loc)76 Java_gnu_xml_libxmlj_sax_GnomeLocator_systemId (JNIEnv * env,
77                                                 jobject self
78 						__attribute__((__unused__)),
79                                                 jobject j_ctx,
80                                                 jobject j_loc)
81 {
82   xmlParserCtxtPtr ctx;
83   xmlSAXLocatorPtr loc;
84   SAXParseContext *sax;
85 
86   ctx = (xmlParserCtxtPtr) xmljAsPointer (env, j_ctx);
87   loc = (xmlSAXLocatorPtr) xmljAsPointer (env, j_loc);
88   sax = (SAXParseContext *) ctx->_private;
89 
90   return sax->systemId;
91 }
92 
93 JNIEXPORT jint JNICALL
Java_gnu_xml_libxmlj_sax_GnomeLocator_lineNumber(JNIEnv * env,jobject self,jobject j_ctx,jobject j_loc)94 Java_gnu_xml_libxmlj_sax_GnomeLocator_lineNumber (JNIEnv * env,
95                                                   jobject self
96 						  __attribute__((__unused__)),
97                                                   jobject j_ctx,
98                                                   jobject j_loc)
99 {
100   xmlParserCtxtPtr ctx;
101   xmlSAXLocatorPtr loc;
102 
103   ctx = (xmlParserCtxtPtr) xmljAsPointer (env, j_ctx);
104   loc = (xmlSAXLocatorPtr) xmljAsPointer (env, j_loc);
105   if (ctx == NULL || ctx->input == NULL)
106     {
107       return -1;
108     }
109   return ctx->input->line;
110 }
111 
112 JNIEXPORT jint JNICALL
Java_gnu_xml_libxmlj_sax_GnomeLocator_columnNumber(JNIEnv * env,jobject self,jobject j_ctx,jobject j_loc)113 Java_gnu_xml_libxmlj_sax_GnomeLocator_columnNumber (JNIEnv * env,
114                                                     jobject self
115 						    __attribute__((__unused__)),
116                                                     jobject j_ctx,
117                                                     jobject j_loc)
118 {
119   xmlParserCtxtPtr ctx;
120   xmlSAXLocatorPtr loc;
121 
122   ctx = (xmlParserCtxtPtr) xmljAsPointer (env, j_ctx);
123   loc = (xmlSAXLocatorPtr) xmljAsPointer (env, j_loc);
124   if (ctx == NULL || ctx->input == NULL)
125     {
126       return -1;
127     }
128   return ctx->input->col;
129 }
130 
131 /* -- GnomeXMLReader -- */
132 
133 /*
134  * Entry point for SAX parsing.
135  */
136 JNIEXPORT void JNICALL
Java_gnu_xml_libxmlj_sax_GnomeXMLReader_parseStream(JNIEnv * env,jobject self,jobject in,jbyteArray detectBuffer,jstring publicId,jstring systemId,jstring base,jboolean validate,jboolean contentHandler,jboolean dtdHandler,jboolean entityResolver,jboolean errorHandler,jboolean declarationHandler,jboolean lexicalHandler)137 Java_gnu_xml_libxmlj_sax_GnomeXMLReader_parseStream (JNIEnv * env,
138                                                      jobject self,
139                                                      jobject in,
140                                                      jbyteArray detectBuffer,
141                                                      jstring publicId,
142                                                      jstring systemId,
143                                                      jstring base,
144                                                      jboolean validate,
145                                                      jboolean contentHandler,
146                                                      jboolean dtdHandler,
147                                                      jboolean entityResolver,
148                                                      jboolean errorHandler,
149                                                      jboolean
150                                                      declarationHandler,
151                                                      jboolean lexicalHandler)
152 {
153   xmljParseDocument (env,
154                      self,
155                      in,
156                      detectBuffer,
157                      publicId,
158                      systemId,
159                      base,
160                      validate,
161                      0,
162                      0,
163                      contentHandler,
164                      dtdHandler,
165                      entityResolver,
166                      errorHandler,
167                      declarationHandler,
168                      lexicalHandler,
169                      0);
170 }
171 
172 xmlParserInputPtr
xmljExternalEntityLoader(const char * url,const char * id,xmlParserCtxtPtr ctx)173 xmljExternalEntityLoader (const char *url, const char *id,
174                           xmlParserCtxtPtr ctx)
175 {
176   const xmlChar *systemId;
177   const xmlChar *publicId;
178   xmlParserInputPtr ret;
179 
180   systemId = xmlCharStrdup (url);
181   publicId = xmlCharStrdup (id);
182   /* TODO convert systemId to absolute URI */
183   ret = xmljSAXResolveEntity (ctx, publicId, systemId);
184   if (ret == NULL)
185     {
186       ret = defaultLoader (url, id, ctx);
187     }
188   return ret;
189 }
190 
191 /*
192  * Allocates and configures a SAX handler that can report the various
193  * classes of callback.
194  */
195 xmlSAXHandlerPtr
xmljNewSAXHandler(jboolean contentHandler,jboolean dtdHandler,jboolean entityResolver,jboolean errorHandler,jboolean declarationHandler,jboolean lexicalHandler)196 xmljNewSAXHandler (jboolean contentHandler,
197                    jboolean dtdHandler,
198                    jboolean entityResolver,
199                    jboolean errorHandler,
200                    jboolean declarationHandler,
201                    jboolean lexicalHandler)
202 {
203   xmlSAXHandlerPtr sax;
204 
205   sax = (xmlSAXHandlerPtr) malloc (sizeof (xmlSAXHandler));
206   if (sax == NULL)
207     {
208       return NULL;
209     }
210   memset (sax, 0, sizeof (xmlSAXHandler));
211   xmlSAXVersion (sax, 1); /* TODO SAX2 */
212 
213   if (dtdHandler)
214     {
215       sax->internalSubset = &xmljSAXInternalSubset;
216     }
217   if (defaultLoader == NULL)
218     {
219       defaultLoader = xmlGetExternalEntityLoader ();
220       xmlSetExternalEntityLoader (xmljExternalEntityLoader);
221     }
222   if (entityResolver)
223     {
224       sax->resolveEntity = &xmljSAXResolveEntity;
225     }
226 
227   if (declarationHandler)
228     {
229       sax->entityDecl = &xmljSAXEntityDecl;
230       sax->notationDecl = &xmljSAXNotationDecl;
231       sax->attributeDecl = &xmljSAXAttributeDecl;
232       sax->elementDecl = &xmljSAXElementDecl;
233       sax->unparsedEntityDecl = &xmljSAXUnparsedEntityDecl;
234     }
235 
236   /* We always listen for the locator callback */
237   sax->setDocumentLocator = &xmljSAXSetDocumentLocator;
238   if (contentHandler)
239     {
240       sax->startDocument = &xmljSAXStartDocument;
241       sax->endDocument = &xmljSAXEndDocument;
242       sax->startElement = &xmljSAXStartElement;
243       sax->endElement = &xmljSAXEndElement;
244       sax->characters = &xmljSAXCharacters;
245       sax->ignorableWhitespace = &xmljSAXIgnorableWhitespace;
246       sax->processingInstruction = &xmljSAXProcessingInstruction;
247     }
248 
249   /* We always intercept getEntity */
250   /* TODO this should only be if lexicalHandler */
251   sax->getEntity = &xmljSAXGetEntity;
252   if (lexicalHandler)
253     {
254       sax->getEntity = &xmljSAXGetEntity;
255       sax->reference = &xmljSAXReference;
256       sax->comment = &xmljSAXComment;
257       sax->cdataBlock = &xmljSAXCDataBlock;
258     }
259   else if (contentHandler)
260     {
261       sax->cdataBlock = &xmljSAXCharacters;
262     }
263 
264   if (errorHandler)
265     {
266       sax->warning = &xmljSAXWarning;
267       sax->error = &xmljSAXError;
268       sax->fatalError = &xmljSAXFatalError;
269     }
270 
271   return sax;
272 }
273 
274 /* -- Callback functions -- */
275 
276 void
xmljSAXInternalSubset(void * vctx,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId)277 xmljSAXInternalSubset (void *vctx,
278                        const xmlChar * name,
279                        const xmlChar * publicId, const xmlChar * systemId)
280 {
281   xmlParserCtxtPtr ctx;
282   SAXParseContext *sax;
283   JNIEnv *env;
284   jobject target;
285   jstring j_name;
286   jstring j_publicId;
287   jstring j_systemId;
288 
289   xmlSAX2InternalSubset (vctx, name, publicId, systemId);
290 
291   ctx = (xmlParserCtxtPtr) vctx;
292   sax = (SAXParseContext *) ctx->_private;
293   env = sax->env;
294   target = sax->obj;
295 
296   xmljCheckWellFormed (ctx);
297   if ((*env)->ExceptionOccurred (env))
298     {
299       return;
300     }
301 
302   if (sax->startDTD == NULL)
303     {
304       sax->startDTD =
305         xmljGetMethodID (env,
306                          target,
307                          "startDTD",
308                          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
309       if (sax->startDTD == NULL)
310         {
311           return;
312         }
313     }
314 
315   j_name = xmljNewString (env, name);
316   j_publicId = xmljNewString (env, publicId);
317   j_systemId = xmljNewString (env, systemId);
318 
319   (*env)->CallVoidMethod (env,
320                           target,
321                           sax->startDTD,
322                           j_name,
323                           j_publicId,
324                           j_systemId);
325 }
326 
327 xmlParserInputPtr
xmljSAXResolveEntity(void * vctx,const xmlChar * publicId,const xmlChar * systemId)328 xmljSAXResolveEntity (void *vctx,
329                       const xmlChar * publicId, const xmlChar * systemId)
330 {
331   xmlParserCtxtPtr ctx;
332   SAXParseContext *sax;
333   JNIEnv *env;
334   jobject target;
335   jstring j_publicId;
336   jstring j_systemId;
337   jobject inputStream;
338 
339   /* xmlSAX2ResolveEntity (vctx, publicId, systemId); */
340 
341   ctx = (xmlParserCtxtPtr) vctx;
342   if (ctx->_private == NULL)
343     {
344       /* Not in Kansas */
345       return NULL;
346     }
347   sax = (SAXParseContext *) ctx->_private;
348   env = sax->env;
349   target = sax->obj;
350 
351   if ((*env)->ExceptionOccurred (env))
352     {
353       return NULL;
354     }
355 
356   if (sax->resolveEntity == NULL)
357     {
358       sax->resolveEntity =
359         xmljGetMethodID (env,
360                          target,
361                          "resolveEntity",
362                          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/io/InputStream;");
363       if (sax->resolveEntity == NULL)
364         {
365           return NULL;
366         }
367     }
368 
369   j_publicId = xmljNewString (env, publicId);
370   j_systemId = xmljNewString (env, systemId);
371 
372   inputStream = (*env)->CallObjectMethod (env,
373                                           target,
374                                           sax->resolveEntity,
375                                           j_publicId,
376                                           j_systemId,
377                                           sax->systemId);
378 
379   /* Return an xmlParserInputPtr corresponding to the input stream */
380   if (inputStream != NULL)
381     {
382       jbyteArray detectBuffer;
383       jmethodID getDetectBuffer;
384 
385       /* Get the detect buffer from the NamedInputStream */
386       getDetectBuffer = xmljGetMethodID (env, inputStream, "getDetectBuffer",
387                                          "()[B");
388       if (getDetectBuffer == NULL)
389         {
390           return NULL;
391         }
392       detectBuffer = (*env)->CallObjectMethod (env, inputStream,
393                                                getDetectBuffer);
394 
395       return xmljNewParserInput (env, inputStream, detectBuffer, ctx);
396     }
397   else
398     {
399       return NULL;
400     }
401 }
402 
403 xmlEntityPtr
xmljSAXGetEntity(void * vctx,const xmlChar * name)404 xmljSAXGetEntity (void *vctx __attribute__((__unused__)), const xmlChar * name)
405 {
406   xmlEntityPtr ret;
407 
408   /* TODO */
409   /* ret = xmlSAX2GetEntity (vctx, name); */
410   ret = NULL;
411   return ret;
412 }
413 
414 void
xmljSAXEntityDecl(void * vctx,const xmlChar * name,int type,const xmlChar * publicId,const xmlChar * systemId,xmlChar * content)415 xmljSAXEntityDecl (void *vctx,
416                    const xmlChar * name,
417                    int type,
418                    const xmlChar * publicId,
419                    const xmlChar * systemId,
420                    xmlChar * content)
421 {
422   xmlParserCtxtPtr ctx;
423   SAXParseContext *sax;
424   JNIEnv *env;
425   jobject target;
426   jstring j_name;
427   jstring j_publicId;
428   jstring j_systemId;
429   jstring j_value;
430 
431   xmlSAX2EntityDecl (vctx, name, type, publicId, systemId, content);
432 
433   ctx = (xmlParserCtxtPtr) vctx;
434   sax = (SAXParseContext *) ctx->_private;
435   env = sax->env;
436   target = sax->obj;
437 
438   xmljCheckWellFormed (ctx);
439   if ((*env)->ExceptionOccurred (env))
440     {
441       return;
442     }
443 
444   j_name = xmljNewString (env, name);
445   switch (type)
446     {
447     case XML_INTERNAL_GENERAL_ENTITY:
448     case XML_INTERNAL_PARAMETER_ENTITY:
449     case XML_INTERNAL_PREDEFINED_ENTITY:
450       if (sax->internalEntityDecl == NULL)
451         {
452           sax->internalEntityDecl =
453             xmljGetMethodID (env,
454                              target,
455                              "internalEntityDecl",
456                              "(Ljava/lang/String;Ljava/lang/String;)V");
457           if (sax->internalEntityDecl == NULL)
458             {
459               return;
460             }
461         }
462       j_value = xmljNewString (env, content);
463       (*env)->CallVoidMethod (env,
464                               target,
465                               sax->internalEntityDecl,
466                               j_name,
467                               j_value);
468       break;
469     default:
470       if (sax->externalEntityDecl == NULL)
471         {
472           sax->externalEntityDecl =
473             xmljGetMethodID (env,
474                              target,
475                              "externalEntityDecl",
476                              "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
477           if (sax->externalEntityDecl == NULL)
478             {
479               return;
480             }
481         }
482       j_publicId = xmljNewString (env, publicId);
483       j_systemId = xmljNewString (env, systemId);
484       (*env)->CallVoidMethod (env,
485                               target,
486                               sax->externalEntityDecl,
487                               j_name,
488                               j_publicId,
489                               j_systemId);
490     }
491 }
492 
493 void
xmljSAXNotationDecl(void * vctx,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId)494 xmljSAXNotationDecl (void *vctx,
495                      const xmlChar * name,
496                      const xmlChar * publicId,
497                      const xmlChar * systemId)
498 {
499   xmlParserCtxtPtr ctx;
500   SAXParseContext *sax;
501   JNIEnv *env;
502   jobject target;
503   jstring j_name;
504   jstring j_publicId;
505   jstring j_systemId;
506 
507   xmlSAX2NotationDecl (vctx, name, publicId, systemId);
508 
509   ctx = (xmlParserCtxtPtr) vctx;
510   sax = (SAXParseContext *) ctx->_private;
511   env = sax->env;
512   target = sax->obj;
513 
514   xmljCheckWellFormed (ctx);
515   if ((*env)->ExceptionOccurred (env))
516     {
517       return;
518     }
519 
520   if (sax->notationDecl == NULL)
521     {
522       sax->notationDecl =
523         xmljGetMethodID (env,
524                          target,
525                          "notationDecl",
526                          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
527       if (sax->notationDecl == NULL)
528         {
529           return;
530         }
531     }
532 
533   j_name = xmljNewString (env, name);
534   j_publicId = xmljNewString (env, publicId);
535   j_systemId = xmljNewString (env, systemId);
536 
537   /* Invoke the method */
538   (*env)->CallVoidMethod (env,
539                           target,
540                           sax->notationDecl,
541                           j_name,
542                           j_publicId,
543                           j_systemId);
544 }
545 
546 void
xmljSAXAttributeDecl(void * vctx,const xmlChar * elem,const xmlChar * fullName,int type,int def,const xmlChar * defaultValue,xmlEnumerationPtr tree)547 xmljSAXAttributeDecl (void *vctx,
548                       const xmlChar * elem,
549                       const xmlChar * fullName,
550                       int type,
551                       int def,
552                       const xmlChar * defaultValue,
553                       xmlEnumerationPtr tree)
554 {
555   xmlParserCtxtPtr ctx;
556   SAXParseContext *sax;
557   JNIEnv *env;
558   jobject target;
559   jstring j_eName;
560   jstring j_aName;
561   jstring j_type;
562   jstring j_mode;
563   jstring j_value;
564 
565   xmlSAX2AttributeDecl (vctx, elem, fullName, type, def, defaultValue, tree);
566 
567   ctx = (xmlParserCtxtPtr) vctx;
568   sax = (SAXParseContext *) ctx->_private;
569   env = sax->env;
570   target = sax->obj;
571 
572   xmljCheckWellFormed (ctx);
573   if ((*env)->ExceptionOccurred (env))
574     {
575       return;
576     }
577 
578   if (sax->attributeDecl == NULL)
579     {
580       sax->attributeDecl =
581         xmljGetMethodID (env,
582                          target,
583                          "attributeDecl",
584                          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
585       if (sax->attributeDecl == NULL)
586         {
587           return;
588         }
589     }
590 
591   j_eName = xmljNewString (env, elem);
592   j_aName = xmljNewString (env, fullName);
593   j_type = xmljAttributeTypeName (env, type);
594   j_mode = xmljAttributeModeName (env, def);
595   j_value = xmljNewString (env, defaultValue);
596 
597   (*env)->CallVoidMethod (env,
598                           target,
599                           sax->attributeDecl,
600                           j_eName,
601                           j_aName,
602                           j_type,
603                           j_mode,
604                           j_value);
605 }
606 
607 void
xmljSAXElementDecl(void * vctx,const xmlChar * name,int type,xmlElementContentPtr content)608 xmljSAXElementDecl (void *vctx,
609                     const xmlChar * name,
610                     int type,
611                     xmlElementContentPtr content)
612 {
613   xmlParserCtxtPtr ctx;
614   SAXParseContext *sax;
615   JNIEnv *env;
616   jobject target;
617   jstring j_name;
618   jstring j_model;
619 
620   xmlSAX2ElementDecl (vctx, name, type, content);
621 
622   ctx = (xmlParserCtxtPtr) vctx;
623   sax = (SAXParseContext *) ctx->_private;
624   env = sax->env;
625   target = sax->obj;
626 
627   xmljCheckWellFormed (ctx);
628   if ((*env)->ExceptionOccurred (env))
629     {
630       return;
631     }
632 
633   if (sax->elementDecl == NULL)
634     {
635       sax->elementDecl =
636         xmljGetMethodID (env,
637                          target,
638                          "elementDecl",
639                          "(Ljava/lang/String;Ljava/lang/String;)V");
640       if (sax->elementDecl == NULL)
641         {
642           return;
643         }
644     }
645 
646   j_name = xmljNewString (env, name);
647   j_model = NULL;		/* TODO */
648 
649   (*env)->CallVoidMethod (env,
650                           target,
651                           sax->elementDecl,
652                           j_name,
653                           j_model);
654 }
655 
656 void
xmljSAXUnparsedEntityDecl(void * vctx,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId,const xmlChar * notationName)657 xmljSAXUnparsedEntityDecl (void *vctx,
658                            const xmlChar * name,
659                            const xmlChar * publicId,
660                            const xmlChar * systemId,
661                            const xmlChar * notationName)
662 {
663   xmlParserCtxtPtr ctx;
664   SAXParseContext *sax;
665   JNIEnv *env;
666   jobject target;
667   jstring j_name;
668   jstring j_publicId;
669   jstring j_systemId;
670   jstring j_notationName;
671 
672   xmlSAX2UnparsedEntityDecl (vctx, name, publicId, systemId, notationName);
673 
674   ctx = (xmlParserCtxtPtr) vctx;
675   sax = (SAXParseContext *) ctx->_private;
676   env = sax->env;
677   target = sax->obj;
678 
679   xmljCheckWellFormed (ctx);
680   if ((*env)->ExceptionOccurred (env))
681     {
682       return;
683     }
684 
685   if (sax->unparsedEntityDecl == NULL)
686     {
687       sax->unparsedEntityDecl =
688         xmljGetMethodID (env,
689                          target,
690                          "unparsedEntityDecl",
691                          "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
692       if (sax->unparsedEntityDecl == NULL)
693         {
694           return;
695         }
696     }
697 
698   j_name = xmljNewString (env, name);
699   j_publicId = xmljNewString (env, publicId);
700   j_systemId = xmljNewString (env, systemId);
701   j_notationName = xmljNewString (env, notationName);
702 
703   (*env)->CallVoidMethod (env,
704                           target,
705                           sax->unparsedEntityDecl,
706                           j_name,
707                           j_publicId,
708                           j_systemId,
709                           j_notationName);
710 }
711 
712 void
xmljSAXSetDocumentLocator(void * vctx,xmlSAXLocatorPtr loc)713 xmljSAXSetDocumentLocator (void *vctx, xmlSAXLocatorPtr loc)
714 {
715   xmlParserCtxtPtr ctx;
716   SAXParseContext *sax;
717   JNIEnv *env;
718   jobject target;
719 
720   xmlSAX2SetDocumentLocator (vctx, loc);
721 
722   ctx = (xmlParserCtxtPtr) vctx;
723   sax = (SAXParseContext *) ctx->_private;
724   env = sax->env;
725   target = sax->obj;
726 
727   if (target == NULL)
728     {
729       /* No Java parse context */
730       return;
731     }
732 
733   /* Update locator on sax context */
734   sax->loc = loc;
735   if ((*env)->ExceptionOccurred (env))
736     {
737       return;
738     }
739 
740   if (sax->setDocumentLocator == NULL)
741     {
742       sax->setDocumentLocator = xmljGetMethodID (env,
743                                                  target,
744                                                  "setDocumentLocator",
745                                                  "(Ljava/lang/Object;Ljava/lang/Object;)V");
746       if (sax->setDocumentLocator == NULL)
747         {
748           return;
749         }
750     }
751 
752   (*env)->CallVoidMethod (env,
753                           target,
754                           sax->setDocumentLocator,
755                           xmljAsField (env, ctx),
756                           xmljAsField (env, loc));
757 }
758 
759 void
xmljSAXStartDocument(void * vctx)760 xmljSAXStartDocument (void *vctx)
761 {
762   xmlParserCtxtPtr ctx;
763   SAXParseContext *sax;
764   JNIEnv *env;
765   jobject target;
766 
767   xmlSAX2StartDocument (vctx);
768 
769   ctx = (xmlParserCtxtPtr) vctx;
770   sax = (SAXParseContext *) ctx->_private;
771   env = sax->env;
772   target = sax->obj;
773 
774   xmljCheckWellFormed (ctx);
775   if ((*env)->ExceptionOccurred (env))
776     {
777       return;
778     }
779 
780   if (sax->startDocument == NULL)
781     {
782       sax->startDocument = xmljGetMethodID (env,
783                                             target,
784                                             "startDocument",
785                                             "(Z)V");
786       if (sax->startDocument == NULL)
787         {
788           return;
789         }
790     }
791 
792   (*env)->CallVoidMethod (env,
793                           target,
794                           sax->startDocument,
795                           ctx->standalone);
796 }
797 
798 void
xmljSAXEndDocument(void * vctx)799 xmljSAXEndDocument (void *vctx)
800 {
801   xmlParserCtxtPtr ctx;
802   SAXParseContext *sax;
803   JNIEnv *env;
804   jobject target;
805 
806   xmlSAX2EndDocument (vctx);
807 
808   ctx = (xmlParserCtxtPtr) vctx;
809   sax = (SAXParseContext *) ctx->_private;
810   env = sax->env;
811   target = sax->obj;
812 
813   xmljCheckWellFormed (ctx);
814   if ((*env)->ExceptionOccurred (env))
815     {
816       return;
817     }
818 
819   if (sax->endDocument == NULL)
820     {
821       sax->endDocument = xmljGetMethodID (env,
822                                           target,
823                                           "endDocument",
824                                           "()V");
825       if (sax->endDocument == NULL)
826         {
827           return;
828         }
829     }
830 
831   (*env)->CallVoidMethod (env,
832                           target,
833                           sax->endDocument);
834 }
835 
836 void
xmljSAXStartElement(void * vctx,const xmlChar * name,const xmlChar ** attrs)837 xmljSAXStartElement (void *vctx,
838                      const xmlChar * name,
839                      const xmlChar ** attrs)
840 {
841   xmlParserCtxtPtr ctx;
842   SAXParseContext *sax;
843   JNIEnv *env;
844   jobject target;
845   jstring j_name;
846   jobjectArray j_attrs;
847   jstring j_attr;
848   jsize len;
849 
850   xmlSAX2StartElement (vctx, name, attrs);
851 
852   ctx = (xmlParserCtxtPtr) vctx;
853   sax = (SAXParseContext *) ctx->_private;
854   env = sax->env;
855   target = sax->obj;
856 
857   xmljCheckWellFormed (ctx);
858   if ((*env)->ExceptionOccurred (env))
859     {
860       return;
861     }
862 
863   if (sax->startElement == NULL)
864     {
865       sax->startElement =
866         xmljGetMethodID (env,
867                          target,
868                          "startElement",
869                          "(Ljava/lang/String;[Ljava/lang/String;)V");
870       if (sax->startElement == NULL)
871         {
872           return;
873         }
874     }
875 
876   j_name = xmljNewString (env, name);
877   /* build attributes array */
878   len = 0;
879   for (len = 0; attrs && attrs[len]; len++)
880     {
881     }
882   if (len)
883     {
884       if (sax->stringClass == NULL)
885         {
886           sax->stringClass = (*env)->FindClass (env, "java/lang/String");
887           if (sax->stringClass == NULL)
888             {
889               fprintf (stderr, "Can't find java.lang.String class!\n");
890               return;
891             }
892         }
893       j_attrs = (*env)->NewObjectArray (env, len, sax->stringClass, NULL);
894       if (j_attrs == NULL)
895         {
896           fprintf (stderr, "Can't allocate attributes array!\n");
897           return;
898         }
899       len = 0;
900       for (len = 0; attrs && attrs[len]; len++)
901         {
902           j_attr = xmljNewString (env, attrs[len]);
903           (*env)->SetObjectArrayElement (env, j_attrs, len, j_attr);
904         }
905 
906       (*env)->CallVoidMethod (env,
907                               target,
908                               sax->startElement,
909                               j_name,
910                               j_attrs);
911       (*env)->DeleteLocalRef (env, j_attrs);
912     }
913   else
914     {
915       (*env)->CallVoidMethod (env,
916                               target,
917                               sax->startElement,
918                               j_name,
919                               NULL);
920 
921     }
922 }
923 
924 void
xmljSAXEndElement(void * vctx,const xmlChar * name)925 xmljSAXEndElement (void *vctx,
926                    const xmlChar * name)
927 {
928   xmlParserCtxtPtr ctx;
929   SAXParseContext *sax;
930   JNIEnv *env;
931   jobject target;
932   jstring j_name;
933 
934   xmlSAX2EndElement (vctx, name);
935 
936   ctx = (xmlParserCtxtPtr) vctx;
937   sax = (SAXParseContext *) ctx->_private;
938   env = sax->env;
939   target = sax->obj;
940 
941   xmljCheckWellFormed (ctx);
942   if ((*env)->ExceptionOccurred (env))
943     {
944       return;
945     }
946 
947   if (sax->endElement == NULL)
948     {
949       sax->endElement = xmljGetMethodID (env,
950                                          target,
951                                          "endElement",
952                                          "(Ljava/lang/String;)V");
953       if (sax->endElement == NULL)
954         {
955           return;
956         }
957     }
958 
959   j_name = xmljNewString (env, name);
960 
961   (*env)->CallVoidMethod (env,
962                           target,
963                           sax->endElement,
964                           j_name);
965 }
966 
967 void
xmljSAXReference(void * vctx,const xmlChar * name)968 xmljSAXReference (void *vctx,
969                   const xmlChar * name)
970 {
971   xmlSAX2Reference (vctx, name);
972 }
973 
974 void
xmljSAXCharacters(void * vctx,const xmlChar * ch,int len)975 xmljSAXCharacters (void *vctx,
976                    const xmlChar * ch,
977                    int len)
978 {
979   xmlParserCtxtPtr ctx;
980   SAXParseContext *sax;
981   JNIEnv *env;
982   jobject target;
983   jstring j_ch;
984   xmlChar *dup;
985 
986   xmlSAX2Characters (vctx, ch, len);
987 
988   ctx = (xmlParserCtxtPtr) vctx;
989   sax = (SAXParseContext *) ctx->_private;
990   env = sax->env;
991   target = sax->obj;
992 
993   xmljCheckWellFormed (ctx);
994   if ((*env)->ExceptionOccurred (env))
995     {
996       return;
997     }
998 
999   if (sax->characters == NULL)
1000     {
1001       sax->characters = xmljGetMethodID (env,
1002                                          target,
1003                                          "characters",
1004                                          "(Ljava/lang/String;)V");
1005       if (sax->characters == NULL)
1006         {
1007           return;
1008         }
1009     }
1010 
1011   dup = xmlStrndup (ch, len);
1012   j_ch = xmljNewString (env, dup);
1013 
1014   (*env)->CallVoidMethod (env,
1015                           target,
1016                           sax->characters,
1017                           j_ch);
1018   xmlFree (dup);
1019 }
1020 
1021 void
xmljSAXIgnorableWhitespace(void * vctx,const xmlChar * ch,int len)1022 xmljSAXIgnorableWhitespace (void *vctx,
1023                             const xmlChar * ch,
1024                             int len)
1025 {
1026   xmlParserCtxtPtr ctx;
1027   SAXParseContext *sax;
1028   JNIEnv *env;
1029   jobject target;
1030   jstring j_ch;
1031   xmlChar *dup;
1032 
1033   xmlSAX2IgnorableWhitespace (vctx, ch, len);
1034 
1035   ctx = (xmlParserCtxtPtr) vctx;
1036   sax = (SAXParseContext *) ctx->_private;
1037   env = sax->env;
1038   target = sax->obj;
1039 
1040   xmljCheckWellFormed (ctx);
1041   if ((*env)->ExceptionOccurred (env))
1042     {
1043       return;
1044     }
1045 
1046   if (sax->ignorableWhitespace == NULL)
1047     {
1048       sax->ignorableWhitespace = xmljGetMethodID (env,
1049                                                   target,
1050                                                   "ignorableWhitespace",
1051                                                   "(Ljava/lang/String;)V");
1052       if (sax->ignorableWhitespace == NULL)
1053         {
1054           return;
1055         }
1056     }
1057 
1058   dup = xmlStrndup (ch, len);
1059   j_ch = xmljNewString (env, dup);
1060 
1061   (*env)->CallVoidMethod (env,
1062                           target,
1063                           sax->ignorableWhitespace,
1064                           j_ch);
1065   xmlFree (dup);
1066 }
1067 
1068 void
xmljSAXProcessingInstruction(void * vctx,const xmlChar * targ,const xmlChar * data)1069 xmljSAXProcessingInstruction (void *vctx,
1070                               const xmlChar * targ,
1071                               const xmlChar * data)
1072 {
1073   xmlParserCtxtPtr ctx;
1074   SAXParseContext *sax;
1075   JNIEnv *env;
1076   jobject target;
1077   jstring j_targ;
1078   jstring j_data;
1079 
1080   xmlSAX2ProcessingInstruction (vctx, targ, data);
1081 
1082   ctx = (xmlParserCtxtPtr) vctx;
1083   sax = (SAXParseContext *) ctx->_private;
1084   env = sax->env;
1085   target = sax->obj;
1086 
1087   xmljCheckWellFormed (ctx);
1088   if ((*env)->ExceptionOccurred (env))
1089     {
1090       return;
1091     }
1092 
1093   if (sax->processingInstruction == NULL)
1094     {
1095       sax->processingInstruction =
1096         xmljGetMethodID (env,
1097                          target,
1098                          "processingInstruction",
1099                          "(Ljava/lang/String;Ljava/lang/String;)V");
1100       if (sax->processingInstruction == NULL)
1101         {
1102           return;
1103         }
1104     }
1105 
1106   j_targ = xmljNewString (env, targ);
1107   j_data = xmljNewString (env, data);
1108 
1109   (*env)->CallVoidMethod (env,
1110                           target,
1111                           sax->processingInstruction,
1112                           j_targ,
1113                           j_data);
1114 }
1115 
1116 void
xmljSAXComment(void * vctx,const xmlChar * value)1117 xmljSAXComment (void *vctx,
1118                 const xmlChar * value)
1119 {
1120   xmlParserCtxtPtr ctx;
1121   SAXParseContext *sax;
1122   JNIEnv *env;
1123   jobject target;
1124   jstring j_text;
1125 
1126   xmlSAX2Comment (vctx, value);
1127 
1128   ctx = (xmlParserCtxtPtr) vctx;
1129   sax = (SAXParseContext *) ctx->_private;
1130   env = sax->env;
1131   target = sax->obj;
1132 
1133   xmljCheckWellFormed (ctx);
1134   if ((*env)->ExceptionOccurred (env))
1135     {
1136       return;
1137     }
1138 
1139   if (sax->comment == NULL)
1140     {
1141       sax->comment =
1142         xmljGetMethodID (env,
1143                          target,
1144                          "comment",
1145                          "(Ljava/lang/String;)V");
1146       if (sax->comment == NULL)
1147         {
1148           return;
1149         }
1150     }
1151 
1152   j_text = xmljNewString (env, value);
1153 
1154   (*env)->CallVoidMethod (env,
1155                           target,
1156                           sax->comment,
1157                           j_text);
1158 }
1159 
1160 void
xmljSAXCDataBlock(void * vctx,const xmlChar * ch,int len)1161 xmljSAXCDataBlock (void *vctx,
1162                    const xmlChar * ch,
1163                    int len)
1164 {
1165   xmlParserCtxtPtr ctx;
1166   SAXParseContext *sax;
1167   JNIEnv *env;
1168   jobject target;
1169   jstring j_ch;
1170   xmlChar *dup;
1171 
1172   xmlSAX2CDataBlock (vctx, ch, len);
1173 
1174   ctx = (xmlParserCtxtPtr) vctx;
1175   sax = (SAXParseContext *) ctx->_private;
1176   env = sax->env;
1177   target = sax->obj;
1178 
1179   xmljCheckWellFormed (ctx);
1180   if ((*env)->ExceptionOccurred (env))
1181     {
1182       return;
1183     }
1184 
1185   if (sax->cdataBlock == NULL)
1186     {
1187       sax->cdataBlock =
1188         xmljGetMethodID (env,
1189                          target,
1190                          "cdataBlock",
1191                          "(Ljava/lang/String;)V");
1192       if (sax->cdataBlock == NULL)
1193         {
1194           return;
1195         }
1196     }
1197 
1198   dup = xmlStrndup (ch, len);
1199   j_ch = xmljNewString (env, dup);
1200 
1201   (*env)->CallVoidMethod (env,
1202                           target,
1203                           sax->cdataBlock,
1204                           j_ch);
1205   xmlFree (dup);
1206 }
1207 
1208 void
xmljDispatchError(xmlParserCtxtPtr ctx,xmlSAXLocatorPtr loc,JNIEnv * env,jobject target,jmethodID method,const char * msg,va_list args)1209 xmljDispatchError (xmlParserCtxtPtr ctx,
1210                    xmlSAXLocatorPtr loc,
1211                    JNIEnv *env,
1212                    jobject target,
1213                    jmethodID method,
1214                    const char *msg,
1215                    va_list args)
1216 {
1217   jint lineNumber;
1218   jint columnNumber;
1219   jstring publicId;
1220   jstring systemId;
1221   char buffer[2048] = "";
1222 
1223   if (msg != NULL)
1224     {
1225       vsnprintf (buffer, sizeof buffer, msg, args);
1226     }
1227   lineNumber = loc->getLineNumber (ctx);
1228   columnNumber = loc->getColumnNumber (ctx);
1229   publicId = xmljNewString (env, loc->getPublicId (ctx));
1230   systemId = xmljNewString (env, loc->getSystemId (ctx));
1231   (*env)->CallVoidMethod (env,
1232                           target,
1233                           method,
1234                           (*env)->NewStringUTF (env, buffer),
1235                           lineNumber,
1236                           columnNumber,
1237                           publicId,
1238                           systemId);
1239 }
1240 
1241 void
xmljSAXWarning(void * vctx,const char * msg,...)1242 xmljSAXWarning (void *vctx,
1243                 const char *msg,
1244                 ...)
1245 {
1246   va_list args;
1247 
1248   xmlParserCtxtPtr ctx;
1249   SAXParseContext *sax;
1250   xmlSAXLocatorPtr loc;
1251   JNIEnv *env;
1252   jobject target;
1253 
1254   ctx = (xmlParserCtxtPtr) vctx;
1255   sax = (SAXParseContext *) ctx->_private;
1256   loc = (xmlSAXLocatorPtr) sax->loc;
1257   env = sax->env;
1258   target = sax->obj;
1259 
1260   if ((*env)->ExceptionOccurred (env))
1261     {
1262       return;
1263     }
1264   if (sax->warning == NULL)
1265     {
1266       sax->warning =
1267         xmljGetMethodID (env,
1268                          target,
1269                          "warning",
1270                          "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V");
1271       if (sax->warning == NULL)
1272         {
1273           return;
1274         }
1275     }
1276 
1277   va_start (args, msg);
1278   /* xmlParserWarning (vctx, msg, args); */
1279   xmljDispatchError (ctx, loc, env, target, sax->warning, msg, args);
1280   va_end (args);
1281 }
1282 
1283 void
xmljSAXError(void * vctx,const char * msg,...)1284 xmljSAXError (void *vctx,
1285               const char *msg,
1286               ...)
1287 {
1288   va_list args;
1289 
1290   xmlParserCtxtPtr ctx;
1291   SAXParseContext *sax;
1292   xmlSAXLocatorPtr loc;
1293   JNIEnv *env;
1294   jobject target;
1295 
1296   ctx = (xmlParserCtxtPtr) vctx;
1297   sax = (SAXParseContext *) ctx->_private;
1298   loc = (xmlSAXLocatorPtr) sax->loc;
1299   env = sax->env;
1300   target = sax->obj;
1301 
1302   if ((*env)->ExceptionOccurred (env))
1303     {
1304       return;
1305     }
1306   if (sax->error == NULL)
1307     {
1308       sax->error =
1309         xmljGetMethodID (env,
1310                          target,
1311                          "error",
1312                          "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V");
1313       if (sax->error == NULL)
1314         {
1315           return;
1316         }
1317     }
1318 
1319   va_start (args, msg);
1320   /* xmlParserError (vctx, msg, args); */
1321   xmljDispatchError (ctx, loc, env, target, sax->error, msg, args);
1322   va_end (args);
1323 }
1324 
1325 void
xmljSAXFatalError(void * vctx,const char * msg,...)1326 xmljSAXFatalError (void *vctx,
1327                    const char *msg,
1328                    ...)
1329 {
1330   va_list args;
1331 
1332   xmlParserCtxtPtr ctx;
1333   SAXParseContext *sax;
1334   xmlSAXLocatorPtr loc;
1335   JNIEnv *env;
1336   jobject target;
1337 
1338   ctx = (xmlParserCtxtPtr) vctx;
1339   sax = (SAXParseContext *) ctx->_private;
1340   loc = (xmlSAXLocatorPtr) sax->loc;
1341   env = sax->env;
1342   target = sax->obj;
1343 
1344   if ((*env)->ExceptionOccurred (env))
1345     {
1346       return;
1347     }
1348   if (sax->fatalError == NULL)
1349     {
1350       sax->fatalError =
1351         xmljGetMethodID (env,
1352                          target,
1353                          "fatalError",
1354                          "(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V");
1355       if (sax->fatalError == NULL)
1356         {
1357           return;
1358         }
1359     }
1360 
1361   va_start (args, msg);
1362   /* xmlParserError (vctx, msg, args); */
1363   xmljDispatchError (ctx, loc, env, target, sax->fatalError, msg, args);
1364   va_end (args);
1365 }
1366 
1367 void
xmljCheckWellFormed(xmlParserCtxtPtr ctx)1368 xmljCheckWellFormed (xmlParserCtxtPtr ctx)
1369 {
1370   if (!ctx->wellFormed)
1371     {
1372       xmljSAXFatalError (ctx, "document is not well-formed");
1373     }
1374   if (ctx->validate && !ctx->valid)
1375     {
1376       xmljSAXFatalError (ctx, "document is not valid");
1377     }
1378 }
1379 
1380 /*
1381  * Convert a libxml2 attribute type to a string.
1382  */
1383 jstring
xmljAttributeTypeName(JNIEnv * env,int type)1384 xmljAttributeTypeName (JNIEnv * env, int type)
1385 {
1386   const char *text;
1387 
1388   switch (type)
1389     {
1390     case XML_ATTRIBUTE_CDATA:
1391       text = "CDATA";
1392       break;
1393     case XML_ATTRIBUTE_ID:
1394       text = "ID";
1395       break;
1396     case XML_ATTRIBUTE_IDREF:
1397       text = "IDREF";
1398       break;
1399     case XML_ATTRIBUTE_IDREFS:
1400       text = "IDREFS";
1401       break;
1402     case XML_ATTRIBUTE_NMTOKEN:
1403       text = "NMTOKEN";
1404       break;
1405     case XML_ATTRIBUTE_NMTOKENS:
1406       text = "NMTOKENS";
1407       break;
1408     case XML_ATTRIBUTE_ENTITY:
1409       text = "ID";
1410       break;
1411     case XML_ATTRIBUTE_ENTITIES:
1412       text = "ID";
1413       break;
1414     default:
1415       return NULL;
1416     }
1417 
1418   return (*env)->NewStringUTF (env, text);
1419 }
1420 
1421 /*
1422  * Convert a libxml2 attribute default value type to a string.
1423  */
1424 jstring
xmljAttributeModeName(JNIEnv * env,int type)1425 xmljAttributeModeName (JNIEnv * env, int type)
1426 {
1427   const char *text;
1428 
1429   switch (type)
1430     {
1431     case XML_ATTRIBUTE_IMPLIED:
1432       text = "#IMPLIED";
1433       break;
1434     case XML_ATTRIBUTE_REQUIRED:
1435       text = "#REQUIRED";
1436       break;
1437     case XML_ATTRIBUTE_FIXED:
1438       text = "#FIXED";
1439       break;
1440     default:
1441       return NULL;
1442     }
1443 
1444   return (*env)->NewStringUTF (env, text);
1445 }
1446