/**
   * Write the byte represented by the specified int to the associated channel.
   *
   * @param c The byte to write
   * @return 1 if the byte was written, 0 if not and -1 if there was an error (@see
   *     java.nio.channels.WritableByteChannel.write(java.nio.ByteBuffer))
   * @throws java.io.IOException If there was an exception during IO
   * @throws org.jruby.util.io.BadDescriptorException if the associated channel is already closed
   */
  public int write(int c) throws IOException, BadDescriptorException {
    checkOpen();

    ByteBuffer buf = ByteBuffer.allocate(1);
    buf.put((byte) c);
    buf.flip();

    return internalWrite(buf);
  }
  /**
   * Perform a low-level read of the remaining number of bytes into the specified byte buffer. The
   * incoming bytes will be used to fill the remaining space in the target byte buffer. This is
   * equivalent to the read(2) POSIX function, and like that function it ignores read and write
   * buffers defined elsewhere.
   *
   * @param buffer the java.nio.ByteBuffer in which to put the incoming bytes
   * @return the number of bytes actually read
   * @throws java.io.IOException if there is an exception during IO
   * @throws org.jruby.util.io.BadDescriptorException if the associated channel is already closed
   * @see java.nio.ByteBuffer
   */
  public int read(ByteBuffer buffer) throws IOException, BadDescriptorException {
    checkOpen();

    // TODO: It would be nice to throw a better error for this
    if (!isReadable()) {
      throw new BadDescriptorException();
    }
    ReadableByteChannel readChannel = (ReadableByteChannel) channel;
    int bytesRead = 0;
    bytesRead = readChannel.read(buffer);

    return bytesRead;
  }
  /**
   * Perform a low-level read of the specified number of bytes into the specified byte list. The
   * incoming bytes will be appended to the byte list. This is equivalent to the read(2) POSIX
   * function, and like that function it ignores read and write buffers defined elsewhere.
   *
   * @param number the number of bytes to read
   * @param byteList the byte list on which to append the incoming bytes
   * @return the number of bytes actually read
   * @throws java.io.IOException if there is an exception during IO
   * @throws org.jruby.util.io.BadDescriptorException if the associated channel is already closed.
   * @see org.jruby.util.ByteList
   */
  public int read(int number, ByteList byteList) throws IOException, BadDescriptorException {
    checkOpen();

    byteList.ensure(byteList.length() + number);
    int bytesRead =
        read(
            ByteBuffer.wrap(
                byteList.getUnsafeBytes(), byteList.begin() + byteList.length(), number));
    if (bytesRead > 0) {
      byteList.length(byteList.length() + bytesRead);
    }
    return bytesRead;
  }
Exemple #4
0
  public synchronized int read() throws IOException, BadDescriptorException {
    try {
      descriptor.checkOpen();

      if (ungotc >= 0) {
        int c = ungotc;
        ungotc = -1;
        return c;
      }

      return bufferedRead();
    } catch (EOFException e) {
      eof = true;
      return -1;
    }
  }
Exemple #5
0
  public synchronized int getline(ByteList dst, byte terminator, long limit)
      throws IOException, BadDescriptorException {
    checkReadable();
    ensureRead();
    descriptor.checkOpen();

    int totalRead = 0;
    boolean found = false;
    if (ungotc != -1) {
      dst.append((byte) ungotc);
      found = ungotc == terminator;
      ungotc = -1;
      limit--;
      ++totalRead;
    }
    while (!found) {
      final byte[] bytes = buffer.array();
      final int begin = buffer.arrayOffset() + buffer.position();
      final int end = begin + buffer.remaining();
      int len = 0;
      for (int i = begin; i < end && limit-- > 0 && !found; ++i) {
        found = bytes[i] == terminator;
        ++len;
      }
      if (limit < 1) found = true;

      if (len > 0) {
        dst.append(buffer, len);
        totalRead += len;
      }
      if (!found) {
        int n = refillBuffer();
        if (n <= 0) {
          if (n < 0 && totalRead < 1) {
            return -1;
          }
          break;
        }
      }
    }
    return totalRead;
  }
  /**
   * Write the bytes in the specified byte list to the associated channel.
   *
   * @param buffer the byte list containing the bytes to be written
   * @return the number of bytes actually written
   * @throws java.io.IOException if there is an exception during IO
   * @throws org.jruby.util.io.BadDescriptorException if the associated channel is already closed
   */
  public int internalWrite(ByteBuffer buffer) throws IOException, BadDescriptorException {
    checkOpen();

    // TODO: It would be nice to throw a better error for this
    if (!isWritable()) {
      throw new BadDescriptorException();
    }

    WritableByteChannel writeChannel = (WritableByteChannel) channel;

    // if appendable, we always seek to the end before writing
    if (isSeekable() && originalModes.isAppendable()) {
      // if already in append mode, we don't do our own seeking
      if (!isInAppendMode) {
        FileChannel fileChannel = (FileChannel) channel;
        fileChannel.position(fileChannel.size());
      }
    }

    return writeChannel.write(buffer);
  }
  /**
   * Perform a low-level seek operation on the associated channel if it is instanceof FileChannel,
   * or raise PipeException if it is not a FileChannel. Calls checkOpen to confirm the target
   * channel is open. This is equivalent to the lseek(2) POSIX function, and like that function it
   * bypasses any buffer flushing or invalidation as in ChannelStream.fseek.
   *
   * @param offset the offset value to use
   * @param whence whence to seek
   * @throws java.io.IOException If there is an exception while seeking
   * @throws org.jruby.util.io.InvalidValueException If the value specified for offset or whence is
   *     invalid
   * @throws org.jruby.util.io.PipeException If the target channel is not seekable
   * @throws org.jruby.util.io.BadDescriptorException If the target channel is already closed.
   * @return the new offset into the FileChannel.
   */
  public long lseek(long offset, int whence)
      throws IOException, InvalidValueException, PipeException, BadDescriptorException {
    if (seekableChannel) {
      checkOpen();

      FileChannel fileChannel = (FileChannel) channel;
      try {
        long pos;
        switch (whence) {
          case Stream.SEEK_SET:
            pos = offset;
            fileChannel.position(pos);
            break;
          case Stream.SEEK_CUR:
            pos = fileChannel.position() + offset;
            fileChannel.position(pos);
            break;
          case Stream.SEEK_END:
            pos = fileChannel.size() + offset;
            fileChannel.position(pos);
            break;
          default:
            throw new InvalidValueException();
        }
        return pos;
      } catch (IllegalArgumentException e) {
        throw new InvalidValueException();
      } catch (IOException ioe) {
        // "invalid seek" means it's an ESPIPE, so we rethrow as a PipeException()
        if (ioe.getMessage().equals("Illegal seek")) {
          throw new PipeException();
        }
        throw ioe;
      }
    } else {
      throw new PipeException();
    }
  }
Exemple #8
0
  public synchronized ByteList fgets(ByteList separatorString)
      throws IOException, BadDescriptorException {
    checkReadable();
    ensureRead();

    if (separatorString == null) {
      return readall();
    }

    final ByteList separator =
        (separatorString == PARAGRAPH_DELIMETER) ? PARAGRAPH_SEPARATOR : separatorString;

    descriptor.checkOpen();

    if (feof()) {
      return null;
    }

    int c = read();

    if (c == -1) {
      return null;
    }

    // unread back
    buffer.position(buffer.position() - 1);

    ByteList buf = new ByteList(40);

    byte first = separator.getUnsafeBytes()[separator.getBegin()];

    LineLoop:
    while (true) {
      ReadLoop:
      while (true) {
        byte[] bytes = buffer.array();
        int offset = buffer.position();
        int max = buffer.limit();

        // iterate over remainder of buffer until we find a match
        for (int i = offset; i < max; i++) {
          c = bytes[i];
          if (c == first) {
            // terminate and advance buffer when we find our char
            buf.append(bytes, offset, i - offset);
            if (i >= max) {
              buffer.clear();
            } else {
              buffer.position(i + 1);
            }
            break ReadLoop;
          }
        }

        // no match, append remainder of buffer and continue with next block
        buf.append(bytes, offset, buffer.remaining());
        int read = refillBuffer();
        if (read == -1) break LineLoop;
      }

      // found a match above, check if remaining separator characters match, appending as we go
      for (int i = 0; i < separator.getRealSize(); i++) {
        if (c == -1) {
          break LineLoop;
        } else if (c != separator.getUnsafeBytes()[separator.getBegin() + i]) {
          buf.append(c);
          continue LineLoop;
        }
        buf.append(c);
        if (i < separator.getRealSize() - 1) {
          c = read();
        }
      }
      break;
    }

    if (separatorString == PARAGRAPH_DELIMETER) {
      while (c == separator.getUnsafeBytes()[separator.getBegin()]) {
        c = read();
      }
      ungetc(c);
    }

    return buf;
  }
  /**
   * Write the bytes in the specified byte list to the associated channel.
   *
   * @param buf the byte list containing the bytes to be written
   * @param offset the offset to start at. this is relative to the begin variable in the but
   * @param len the amount of bytes to write. this should not be longer than the buffer
   * @return the number of bytes actually written
   * @throws java.io.IOException if there is an exception during IO
   * @throws org.jruby.util.io.BadDescriptorException if the associated channel is already closed
   */
  public int write(ByteList buf, int offset, int len) throws IOException, BadDescriptorException {
    checkOpen();

    return internalWrite(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin() + offset, len));
  }
  /**
   * Write the bytes in the specified byte list to the associated channel.
   *
   * @param buf the byte list containing the bytes to be written
   * @return the number of bytes actually written
   * @throws java.io.IOException if there is an exception during IO
   * @throws org.jruby.util.io.BadDescriptorException if the associated channel is already closed
   */
  public int write(ByteList buf) throws IOException, BadDescriptorException {
    checkOpen();

    return internalWrite(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin(), buf.length()));
  }
  /**
   * Write the bytes in the specified byte list to the associated channel.
   *
   * @param buffer the byte list containing the bytes to be written
   * @return the number of bytes actually written
   * @throws java.io.IOException if there is an exception during IO
   * @throws org.jruby.util.io.BadDescriptorException if the associated channel is already closed
   */
  public int write(ByteBuffer buffer) throws IOException, BadDescriptorException {
    checkOpen();

    return internalWrite(buffer);
  }