Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <stddef.h>
     29 #include <stdio.h>
     30 
     31 #include "jni.h"
     32 #include "jni_util.h"
     33 #include "jvm.h"
     34 #include "io_util.h"
     35 #include "io_util_md.h"
     36 
     37 /* IO helper functions */
     38 
     39 jint
     40 readSingle(JNIEnv *env, jobject this, jfieldID fid) {
     41     jint nread;
     42     char ret;
     43     FD fd = GET_FD(this, fid);
     44     if (fd == -1) {
     45         JNU_ThrowIOException(env, "Stream Closed");
     46         return -1;
     47     }
     48     nread = (jint)IO_Read(fd, &ret, 1);
     49     if (nread == 0) { /* EOF */
     50         return -1;
     51     } else if (nread == JVM_IO_ERR) { /* error */
     52         JNU_ThrowIOExceptionWithLastError(env, "Read error");
     53     } else if (nread == JVM_IO_INTR) {
     54         JNU_ThrowByName(env, "java/io/InterruptedIOException", NULL);
     55     }
     56     return ret & 0xFF;
     57 }
     58 
     59 /* The maximum size of a stack-allocated buffer.
     60  */
     61 #define BUF_SIZE 8192
     62 
     63 /*
     64  * Returns true if the array slice defined by the given offset and length
     65  * is out of bounds.
     66  */
     67 static int
     68 outOfBounds(JNIEnv *env, jint off, jint len, jbyteArray array) {
     69     return ((off < 0) ||
     70             (len < 0) ||
     71             // We are very careful to avoid signed integer overflow,
     72             // the result of which is undefined in C.
     73             ((*env)->GetArrayLength(env, array) - off < len));
     74 }
     75 
     76 jint
     77 readBytes(JNIEnv *env, jobject this, jbyteArray bytes,
     78           jint off, jint len, jfieldID fid)
     79 {
     80     jint nread;
     81     char stackBuf[BUF_SIZE];
     82     char *buf = NULL;
     83     FD fd;
     84 
     85     if (IS_NULL(bytes)) {
     86         JNU_ThrowNullPointerException(env, NULL);
     87         return -1;
     88     }
     89 
     90     if (outOfBounds(env, off, len, bytes)) {
     91         JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL);
     92         return -1;
     93     }
     94 
     95     if (len == 0) {
     96         return 0;
     97     } else if (len > BUF_SIZE) {
     98         buf = malloc(len);
     99         if (buf == NULL) {
    100             JNU_ThrowOutOfMemoryError(env, NULL);
    101             return 0;
    102         }
    103     } else {
    104         buf = stackBuf;
    105     }
    106 
    107     fd = GET_FD(this, fid);
    108     if (fd == -1) {
    109         JNU_ThrowIOException(env, "Stream Closed");
    110         nread = -1;
    111     } else {
    112         nread = (jint)IO_Read(fd, buf, len);
    113         if (nread > 0) {
    114             (*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf);
    115         } else if (nread == JVM_IO_ERR) {
    116             JNU_ThrowIOExceptionWithLastError(env, "Read error");
    117         } else if (nread == JVM_IO_INTR) {
    118             JNU_ThrowByName(env, "java/io/InterruptedIOException", NULL);
    119         } else { /* EOF */
    120             nread = -1;
    121         }
    122     }
    123 
    124     if (buf != stackBuf) {
    125         free(buf);
    126     }
    127     return nread;
    128 }
    129 
    130 void
    131 writeSingle(JNIEnv *env, jobject this, jint byte, jboolean append, jfieldID fid) {
    132     // Discard the 24 high-order bits of byte. See OutputStream#write(int)
    133     char c = (char) byte;
    134     jint n;
    135     FD fd = GET_FD(this, fid);
    136     if (fd == -1) {
    137         JNU_ThrowIOException(env, "Stream Closed");
    138         return;
    139     }
    140     if (append == JNI_TRUE) {
    141         n = (jint)IO_Append(fd, &c, 1);
    142     } else {
    143         n = (jint)IO_Write(fd, &c, 1);
    144     }
    145     if (n == JVM_IO_ERR) {
    146         JNU_ThrowIOExceptionWithLastError(env, "Write error");
    147     } else if (n == JVM_IO_INTR) {
    148         JNU_ThrowByName(env, "java/io/InterruptedIOException", NULL);
    149     }
    150 }
    151 
    152 void
    153 writeBytes(JNIEnv *env, jobject this, jbyteArray bytes,
    154            jint off, jint len, jboolean append, jfieldID fid)
    155 {
    156     jint n;
    157     char stackBuf[BUF_SIZE];
    158     char *buf = NULL;
    159     FD fd;
    160 
    161     if (IS_NULL(bytes)) {
    162         JNU_ThrowNullPointerException(env, NULL);
    163         return;
    164     }
    165 
    166     if (outOfBounds(env, off, len, bytes)) {
    167         JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", NULL);
    168         return;
    169     }
    170 
    171     if (len == 0) {
    172         return;
    173     } else if (len > BUF_SIZE) {
    174         buf = malloc(len);
    175         if (buf == NULL) {
    176             JNU_ThrowOutOfMemoryError(env, NULL);
    177             return;
    178         }
    179     } else {
    180         buf = stackBuf;
    181     }
    182 
    183     (*env)->GetByteArrayRegion(env, bytes, off, len, (jbyte *)buf);
    184 
    185     if (!(*env)->ExceptionOccurred(env)) {
    186         off = 0;
    187         while (len > 0) {
    188             fd = GET_FD(this, fid);
    189             if (fd == -1) {
    190                 JNU_ThrowIOException(env, "Stream Closed");
    191                 break;
    192             }
    193             if (append == JNI_TRUE) {
    194                 n = (jint)IO_Append(fd, buf+off, len);
    195             } else {
    196                 n = (jint)IO_Write(fd, buf+off, len);
    197             }
    198             if (n == JVM_IO_ERR) {
    199                 JNU_ThrowIOExceptionWithLastError(env, "Write error");
    200                 break;
    201             } else if (n == JVM_IO_INTR) {
    202                 JNU_ThrowByName(env, "java/io/InterruptedIOException", NULL);
    203                 break;
    204             }
    205             off += n;
    206             len -= n;
    207         }
    208     }
    209     if (buf != stackBuf) {
    210         free(buf);
    211     }
    212 }
    213 
    214 void
    215 throwFileNotFoundException(JNIEnv *env, jstring path)
    216 {
    217     char buf[256];
    218     jint n;
    219     jobject x;
    220     jstring why = NULL;
    221 
    222     n = JVM_GetLastErrorString(buf, sizeof(buf));
    223     if (n > 0) {
    224         why = JNU_NewStringPlatform(env, buf);
    225     }
    226     x = JNU_NewObjectByName(env,
    227                             "java/io/FileNotFoundException",
    228                             "(Ljava/lang/String;Ljava/lang/String;)V",
    229                             path, why);
    230     if (x != NULL) {
    231         (*env)->Throw(env, x);
    232     }
    233 }
    234