2 Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 #include "xmlj_error.h"
40 #include "xmlj_node.h"
42 #include "xmlj_util.h"
49 #include <libxml/xmlIO.h>
50 #include <libxml/parserInternals.h>
54 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
55 #define UNSIGN(a) (((a) < 0) ? ((a) + 0x100) : (a))
57 #define DETECT_BUFFER_SIZE 50
59 typedef struct _OutputStreamContext
64 jmethodID outputStreamWriteFunc
;
65 jmethodID outputStreamCloseFunc
;
70 typedef struct _InputStreamContext
75 jmethodID inputStreamReadFunc
;
76 jmethodID inputStreamCloseFunc
;
77 jobject bufferByteArray
;
83 InputStreamContext
*xmljNewInputStreamContext (JNIEnv
* env
,
86 void xmljFreeInputStreamContext (InputStreamContext
* inContext
);
88 int xmljInputReadCallback (void *context
, char *buffer
, int len
);
90 int xmljInputCloseCallback (void *context
);
92 int xmljOutputWriteCallback (void *context
, const char *buffer
, int len
);
94 int xmljOutputCloseCallback (void *context
);
96 OutputStreamContext
*xmljNewOutputStreamContext (JNIEnv
* env
,
97 jobject outputStream
);
100 xmljFreeOutputStreamContext (OutputStreamContext
* outContext
);
103 xmljDetectCharEncoding (JNIEnv
* env
, jbyteArray buffer
);
106 xmljOutputWriteCallback (void *context
, const char *buffer
, int len
)
108 OutputStreamContext
*outContext
;
110 jbyteArray byteArray
;
112 outContext
= (OutputStreamContext
*) context
;
113 env
= outContext
->env
;
114 byteArray
= (*env
)->NewByteArray (env
, len
);
118 (*env
)->SetByteArrayRegion (env
, byteArray
, 0, len
, (jbyte
*) buffer
);
120 (*env
)->CallVoidMethod (env
,
121 outContext
->outputStream
,
122 outContext
->outputStreamWriteFunc
, byteArray
);
124 (*env
)->DeleteLocalRef (env
, byteArray
);
126 return (*env
)->ExceptionOccurred (env
) ? -1 : len
;
130 /* Out of memory, signal error */
136 xmljOutputCloseCallback (void *context
)
138 OutputStreamContext
*outContext
;
141 outContext
= (OutputStreamContext
*) context
;
142 env
= outContext
->env
;
143 (*env
)->CallVoidMethod (env
,
144 outContext
->outputStream
,
145 outContext
->outputStreamCloseFunc
);
147 return (*env
)->ExceptionOccurred (env
) ? -1 : 0;
151 xmljInputReadCallback (void *context
, char *buffer
, int len
)
153 InputStreamContext
*inContext
;
158 inContext
= (InputStreamContext
*) context
;
159 env
= inContext
->env
;
162 for (offset
= 0; offset
< len
&& nread
>= 0;)
164 nread
= (*env
)->CallIntMethod (env
,
165 inContext
->inputStream
,
166 inContext
->inputStreamReadFunc
,
167 inContext
->bufferByteArray
,
168 0, MIN (len
- offset
,
169 inContext
->bufferLength
));
173 (*env
)->GetByteArrayRegion (env
,
174 inContext
->bufferByteArray
,
175 0, nread
, ((jbyte
*) buffer
) + offset
);
181 return (*env
)->ExceptionOccurred (env
) ? -1 : offset
;
185 xmljInputCloseCallback (void *context
)
187 InputStreamContext
*inContext
;
190 inContext
= (InputStreamContext
*) context
;
191 env
= inContext
->env
;
192 (*env
)->CallVoidMethod (env
, inContext
->inputStream
,
193 inContext
->inputStreamCloseFunc
);
195 return (*env
)->ExceptionOccurred (env
) ? -1 : 0;
199 xmljNewInputStreamContext (JNIEnv
* env
, jobject inputStream
)
201 jclass inputStreamClass
;
202 InputStreamContext
*result
;
204 inputStreamClass
= (*env
)->FindClass (env
, "java/io/InputStream");
205 if (inputStreamClass
== NULL
)
209 result
= (InputStreamContext
*) malloc (sizeof (InputStreamContext
));
216 result
->inputStream
= inputStream
;
217 result
->inputStreamReadFunc
=
218 (*env
)->GetMethodID (env
, inputStreamClass
, "read", "([BII)I");
219 result
->inputStreamCloseFunc
=
220 (*env
)->GetMethodID (env
, inputStreamClass
, "close", "()V");
221 result
->bufferLength
= 4096;
222 result
->bufferByteArray
= (*env
)->NewByteArray (env
, result
->bufferLength
);
227 xmljFreeInputStreamContext (InputStreamContext
* inContext
)
231 env
= inContext
->env
;
232 (*env
)->DeleteLocalRef (env
, inContext
->bufferByteArray
);
236 OutputStreamContext
*
237 xmljNewOutputStreamContext (JNIEnv
* env
, jobject outputStream
)
239 jclass outputStreamClass
;
240 OutputStreamContext
*result
;
242 outputStreamClass
= (*env
)->FindClass (env
, "java/io/OutputStream");
243 if (outputStreamClass
== NULL
)
247 result
= (OutputStreamContext
*) malloc (sizeof (OutputStreamContext
));
254 result
->outputStream
= outputStream
;
255 result
->outputStreamWriteFunc
=
256 (*env
)->GetMethodID (env
, outputStreamClass
, "write", "([B)V");
257 result
->outputStreamCloseFunc
=
258 (*env
)->GetMethodID (env
, outputStreamClass
, "close", "()V");
264 xmljFreeOutputStreamContext (OutputStreamContext
* outContext
)
270 xmljNewSAXParseContext (JNIEnv
* env
, jobject obj
, xmlParserCtxtPtr ctx
,
271 jstring publicId
, jstring systemId
)
273 SAXParseContext
*ret
;
275 ret
= (SAXParseContext
*) malloc (sizeof (SAXParseContext
));
281 ret
->publicId
= publicId
;
282 ret
->systemId
= systemId
;
284 ret
->startDTD
= NULL
;
285 ret
->externalEntityDecl
= NULL
;
286 ret
->internalEntityDecl
= NULL
;
287 ret
->resolveEntity
= NULL
;
288 ret
->notationDecl
= NULL
;
289 ret
->attributeDecl
= NULL
;
290 ret
->elementDecl
= NULL
;
291 ret
->unparsedEntityDecl
= NULL
;
292 ret
->setDocumentLocator
= NULL
;
293 ret
->startDocument
= NULL
;
294 ret
->endDocument
= NULL
;
295 ret
->startElement
= NULL
;
296 ret
->endElement
= NULL
;
297 ret
->characters
= NULL
;
298 ret
->ignorableWhitespace
= NULL
;
299 ret
->processingInstruction
= NULL
;
301 ret
->cdataBlock
= NULL
;
304 ret
->fatalError
= NULL
;
306 ret
->resolveURIAndOpen
= NULL
;
307 ret
->stringClass
= NULL
;
312 xmljFreeSAXParseContext (SAXParseContext
* saxCtx
)
318 xmljDetectCharEncoding (JNIEnv
* env
, jbyteArray buffer
)
325 return XML_CHAR_ENCODING_ERROR
;
327 nread
= (*env
)->GetArrayLength (env
, buffer
);
330 jbyte nativeBuffer
[DETECT_BUFFER_SIZE
+ 1];
331 unsigned char converted
[DETECT_BUFFER_SIZE
+ 1];
334 memset (nativeBuffer
, 0, DETECT_BUFFER_SIZE
+ 1);
335 (*env
)->GetByteArrayRegion (env
, buffer
, 0, nread
, nativeBuffer
);
336 /* Convert from signed to unsigned */
337 for (i
= 0; i
< DETECT_BUFFER_SIZE
+ 1; i
++)
339 converted
[i
] = UNSIGN (nativeBuffer
[i
]);
341 ret
= xmlDetectCharEncoding (converted
, nread
);
345 ret
= XML_CHAR_ENCODING_NONE
;
351 xmljNewParserContext (JNIEnv
* env
,
353 jbyteArray detectBuffer
,
359 jboolean expandEntities
,
360 jboolean loadEntities
)
362 InputStreamContext
*inputContext
;
363 xmlCharEncoding encoding
;
364 xmlParserCtxtPtr ctx
;
367 encoding
= xmljDetectCharEncoding (env
, detectBuffer
);
368 if (encoding
!= XML_CHAR_ENCODING_ERROR
)
370 inputContext
= xmljNewInputStreamContext (env
, inputStream
);
371 if (NULL
!= inputContext
)
373 /* NOTE: userdata must be NULL for DOM to work */
374 ctx
= xmlCreateIOParserCtxt (NULL
,
376 xmljInputReadCallback
,
377 xmljInputCloseCallback
,
384 /* Set parsing options */
388 options
|= XML_PARSE_DTDVALID
;
392 options
|= XML_PARSE_NOCDATA
;
396 options
|= XML_PARSE_NOENT
;
400 options
|= XML_PARSE_DTDLOAD
;
402 if (xmlCtxtUseOptions (ctx
, options
))
404 xmljThrowException (env
,
405 "java/lang/RuntimeException",
406 "Unable to set xmlParserCtxtPtr options");
410 ctx
->input
->directory
=
411 (*env
)->GetStringUTFChars (env
, base
, 0);
415 xmljFreeInputStreamContext (inputContext
);
422 xmljFreeParserContext (xmlParserCtxtPtr ctx
)
424 InputStreamContext
*inputStreamContext
= NULL
;
426 if (ctx
->input
!= NULL
&& ctx
->input
->buf
!= NULL
)
429 = (InputStreamContext
*) ctx
->input
->buf
->context
;
432 xmlFreeParserCtxt (ctx
);
433 if (inputStreamContext
!= NULL
)
435 xmljFreeInputStreamContext (inputStreamContext
);
440 xmljParseDocument (JNIEnv
* env
,
443 jbyteArray detectBuffer
,
449 jboolean expandEntities
,
450 jboolean contentHandler
,
452 jboolean entityResolver
,
453 jboolean errorHandler
,
454 jboolean declarationHandler
,
455 jboolean lexicalHandler
,
458 xmlParserCtxtPtr ctx
;
459 SAXParseContext
*saxCtx
;
460 xmlSAXHandlerPtr sax
;
462 ctx
= xmljNewParserContext (env
, in
, detectBuffer
, publicId
, systemId
, base
,
463 validate
, coalesce
, expandEntities
,
467 saxCtx
= xmljNewSAXParseContext (env
, self
, ctx
, publicId
, systemId
);
470 sax
= xmljNewSAXHandler (contentHandler
,
478 return xmljParseDocument2 (env
,
484 xmljFreeSAXParseContext (saxCtx
);
486 xmljFreeParserContext (ctx
);
488 if (!(*env
)->ExceptionOccurred (env
))
490 xmljThrowException (env
, "java/io/IOException",
491 "Unable to create parser context");
497 xmljParseDocument2 (JNIEnv
* env
,
498 xmlParserCtxtPtr ctx
,
499 SAXParseContext
*saxCtx
,
500 xmlSAXHandlerPtr sax
,
503 xmlSAXHandlerPtr orig
;
507 ctx
->_private
= saxCtx
;
512 xmljSetThreadContext (saxCtx
);
514 ret
= xmlParseDocument (ctx
);
518 const char *msg
= ctx
->lastError
.message
;
522 xmljSAXFatalError (ctx
, msg
);
525 xmljThrowDOMException (env
, ret
, msg
);
528 xmljThrowException (env
,
529 "javax/xml/transform/TransformerException",
534 xmljClearThreadContext ();
538 xmljFreeSAXParseContext (saxCtx
);
539 xmljFreeParserContext (ctx
);
540 xmljClearStringCache ();
545 xmljNewParserInput (JNIEnv
* env
,
547 jbyteArray detectBuffer
,
548 xmlParserCtxtPtr parserContext
)
550 xmlParserInputPtr ret
;
551 xmlParserInputBufferPtr input
;
552 xmlCharEncoding encoding
;
554 encoding
= xmljDetectCharEncoding (env
, detectBuffer
);
555 if (encoding
!= XML_CHAR_ENCODING_ERROR
)
557 input
= xmljNewParserInputBuffer (env
, inputStream
, encoding
);
560 ret
= xmlNewIOInputStream (parserContext
, input
, encoding
);
563 xmlFreeParserInputBuffer (input
);
568 xmlParserInputBufferPtr
569 xmljNewParserInputBuffer (JNIEnv
* env
,
570 jobject inputStream
, xmlCharEncoding encoding
)
572 xmlParserInputBufferPtr ret
;
573 InputStreamContext
*inputContext
;
575 inputContext
= xmljNewInputStreamContext (env
, inputStream
);
576 if (NULL
!= inputContext
)
578 ret
= xmlParserInputBufferCreateIO (&xmljInputReadCallback
,
579 &xmljInputCloseCallback
,
580 inputContext
, encoding
);
583 xmljFreeInputStreamContext (inputContext
);
589 xmljSaveFileToJavaOutputStream (JNIEnv
* env
, jobject outputStream
,
591 const char *outputEncodingName
)
593 OutputStreamContext
*outputContext
=
594 xmljNewOutputStreamContext (env
, outputStream
);
596 xmlCharEncoding outputEncoding
= xmlParseCharEncoding (outputEncodingName
);
598 xmlOutputBufferPtr outputBuffer
=
599 xmlOutputBufferCreateIO (xmljOutputWriteCallback
,
600 xmljOutputCloseCallback
,
602 xmlGetCharEncodingHandler (outputEncoding
));
604 /* Write result to output stream */
606 xmlSaveFileTo (outputBuffer
, tree
, outputEncodingName
);
608 xmljFreeOutputStreamContext (outputContext
);
613 xmljResolveURI (SaxErrorContext * saxErrorContext,
614 const char *URL, const char *ID)
616 JNIEnv *env = saxErrorContext->env;
618 jstring hrefString = (*env)->NewStringUTF (env, URL);
619 jstring baseString = saxErrorContext->systemId;
621 jobject sourceWrapper = (*env)->CallObjectMethod (env,
628 (*env)->DeleteLocalRef (env, hrefString);
630 if (NULL == sourceWrapper)
636 jobject sourceInputStream = (*env)->CallObjectMethod (env,
639 getInputStreamMethodID);
641 (*env)->DeleteLocalRef (env, sourceWrapper);
643 if ((*env)->ExceptionOccurred (env))
645 -* Report to ErrorAdapter here? *-
649 return sourceInputStream;
654 xmljResolveURIAndOpen (SAXParseContext
*saxContext
,
658 jobject libxmlDocument
;
660 JNIEnv
*env
= saxContext
->env
;
662 jstring hrefString
= (*env
)->NewStringUTF (env
, URL
);
663 jstring baseString
= saxContext
->systemId
;
665 if (saxContext
->resolveURIAndOpen
== NULL
)
667 jclass cls
= (*env
)->GetObjectClass (env
, saxContext
->obj
);
668 saxContext
->resolveURIAndOpen
=
669 (*env
)->GetMethodID (env
, cls
, "resolveURIAndOpen",
670 "Ljava/lang/String;Ljava/lang/String)Lgnu/xml/libxmlj/transform/LibxmlDocument;");
673 (*env
)->CallObjectMethod (env
,
675 saxContext
->resolveURIAndOpen
,
679 doc
= (xmlDocPtr
) xmljGetNodeID (env
, libxmlDocument
);
681 (*env
)->DeleteLocalRef (env
, libxmlDocument
);
683 if ((*env
)->ExceptionOccurred (env
))
685 /* Report to ErrorAdapter here? */
695 xmljLoadExternalEntity (const char *URL, const char *ID,
696 xmlParserCtxtPtr ctxt)
698 SaxErrorContext *saxErrorContext = xmljGetThreadContext ();
700 JNIEnv *env = saxErrorContext->env;
702 jstring hrefString = (*env)->NewStringUTF (env, URL);
703 jstring baseString = saxErrorContext->systemId;
705 jobject sourceWrapper = (*env)->CallObjectMethod (env,
713 (*env)->DeleteLocalRef (env, hrefString);
715 if (NULL == sourceWrapper)
721 InputStreamContext *inputContext;
722 xmlParserInputBufferPtr inputBuffer;
723 xmlParserInputPtr inputStream;
725 jobject sourceInputStream = (*env)->CallObjectMethod (env,
728 getInputStreamMethodID);
730 (*env)->DeleteLocalRef (env, sourceWrapper);
732 if ((*env)->ExceptionOccurred (env))
734 -* Report to ErrorAdapter *-
738 inputContext = xmljNewInputStreamContext (env, sourceInputStream);
741 = xmlParserInputBufferCreateIO (xmljInputReadCallback,
742 xmljInputCloseCallback,
743 inputContext, XML_CHAR_ENCODING_NONE);
745 inputStream = xmlNewInputStream (ctxt);
746 if (inputStream == NULL)
751 inputStream->filename = NULL;
752 inputStream->directory = NULL;
753 inputStream->buf = inputBuffer;
755 inputStream->base = inputStream->buf->buffer->content;
756 inputStream->cur = inputStream->buf->buffer->content;
757 inputStream->end = &inputStream->base[inputStream->buf->buffer->use];
758 if ((ctxt->directory == NULL) && (inputStream->directory != NULL))
760 (char *) xmlStrdup ((const xmlChar *) inputStream->directory);
761 return (inputStream);
765 /* Key for the thread-specific buffer */
766 static pthread_key_t thread_context_key
;
768 /* Once-only initialisation of the key */
769 static pthread_once_t thread_context_once
= PTHREAD_ONCE_INIT
;
772 thread_context_key_alloc (void);
774 /* Allocate the key */
776 thread_context_key_alloc ()
778 pthread_key_create (&thread_context_key
, NULL
);
782 xmljSetThreadContext (SAXParseContext
* context
)
784 pthread_once (&thread_context_once
, thread_context_key_alloc
);
785 pthread_setspecific (thread_context_key
, context
);
789 xmljClearThreadContext (void)
791 pthread_setspecific (thread_context_key
, NULL
);
794 /* Return the thread-specific buffer */
796 xmljGetThreadContext (void)
798 return (SAXParseContext
*) pthread_getspecific (thread_context_key
);