Beispiel #1
0
  public synchronized int writenonblock(ByteList buf) throws IOException, BadDescriptorException {
    checkWritable();
    ensureWrite();

    // Ruby ignores empty syswrites
    if (buf == null || buf.length() == 0) return 0;

    if (buffer.position() != 0 && !flushWrite(false)) return 0;

    if (descriptor.getChannel() instanceof SelectableChannel) {
      SelectableChannel selectableChannel = (SelectableChannel) descriptor.getChannel();
      synchronized (selectableChannel.blockingLock()) {
        boolean oldBlocking = selectableChannel.isBlocking();
        try {
          if (oldBlocking) {
            selectableChannel.configureBlocking(false);
          }
          return descriptor.write(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin(), buf.length()));
        } finally {
          if (oldBlocking) {
            selectableChannel.configureBlocking(oldBlocking);
          }
        }
      }
    } else {
      // can't set nonblocking, so go ahead with it...not much else we can do
      return descriptor.write(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin(), buf.length()));
    }
  }
  /**
   * 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;
  }
Beispiel #3
0
  @JRubyMethod(name = "ungetc", required = 1)
  public IRubyObject ungetc(IRubyObject arg) {
    checkReadable();

    int c = RubyNumeric.num2int(arg);
    if (pos == 0) return getRuntime().getNil();
    internal.modify();
    pos--;

    ByteList bytes = internal.getByteList();

    if (bytes.length() <= pos) {
      bytes.length((int) pos + 1);
    }

    bytes.set((int) pos, c);
    return getRuntime().getNil();
  }
  @JRubyMethod(name = "truncate", required = 1)
  @Override
  public IRubyObject truncate(IRubyObject arg) {
    checkWritable();

    int len = RubyFixnum.fix2int(arg);
    if (len < 0) {
      throw getRuntime().newErrnoEINVALError("negative legnth");
    }

    data.internal.modify();
    ByteList buf = data.internal.getByteList();
    if (len < buf.length()) {
      Arrays.fill(buf.getUnsafeBytes(), len, buf.length(), (byte) 0);
    }
    buf.length(len);
    return arg;
  }
  private void ungetcCommon(int c) {
    data.internal.modify();
    data.pos--;

    ByteList bytes = data.internal.getByteList();

    if (isEndOfString()) bytes.length((int) data.pos + 1);

    bytes.set((int) data.pos, c);
  }
Beispiel #6
0
 public SymbolNode(ISourcePosition position, ByteList value) {
   super(position, false);
   this.name = value.toString().intern();
   // FIXME: A full scan to determine whether we should back off to US-ASCII.  Lexer should just do
   // this properly.
   if (value.lengthEnc() == value.length()) {
     this.encoding = USASCIIEncoding.INSTANCE;
   } else {
     this.encoding = value.getEncoding();
   }
 }
Beispiel #7
0
  private IRubyObject internalGets(ThreadContext context, IRubyObject[] args) {
    Ruby runtime = context.getRuntime();

    if (pos < internal.getByteList().realSize && !eof) {
      boolean isParagraph = false;

      ByteList sep;
      if (args.length > 0) {
        if (args[0].isNil()) {
          ByteList buf =
              internal
                  .getByteList()
                  .makeShared((int) pos, internal.getByteList().realSize - (int) pos);
          pos += buf.realSize;
          return RubyString.newString(runtime, buf);
        }
        sep = args[0].convertToString().getByteList();
        if (sep.realSize == 0) {
          isParagraph = true;
          sep = Stream.PARAGRAPH_SEPARATOR;
        }
      } else {
        sep = ((RubyString) runtime.getGlobalVariables().get("$/")).getByteList();
      }

      ByteList ss = internal.getByteList();

      if (isParagraph) {
        swallowLF(ss);
        if (pos == ss.realSize) {
          return runtime.getNil();
        }
      }

      int ix = ss.indexOf(sep, (int) pos);

      ByteList add;
      if (-1 == ix) {
        ix = internal.getByteList().realSize;
        add = ByteList.EMPTY_BYTELIST;
      } else {
        add = isParagraph ? NEWLINE : sep;
      }

      ByteList line = new ByteList(ix - (int) pos + add.length());
      line.append(internal.getByteList(), (int) pos, ix - (int) pos);
      line.append(add);
      pos = ix + add.realSize;
      lineno++;

      return RubyString.newString(runtime, line);
    }
    return runtime.getNil();
  }
Beispiel #8
0
    public void put(
        ThreadContext context,
        StructLayout.Storage cache,
        Member m,
        IRubyObject ptr,
        IRubyObject value) {
      ByteList bl = value.convertToString().getByteList();

      MemoryPointer mem = MemoryPointer.allocate(context.getRuntime(), 1, bl.length() + 1, false);
      //
      // Keep a reference to the temporary memory in the cache so it does
      // not get freed by the GC until the struct is freed
      //
      cache.putReference(m, mem);

      MemoryIO io = mem.getMemoryIO();
      io.put(0, bl.getUnsafeBytes(), bl.begin(), bl.length());
      io.putByte(bl.length(), (byte) 0);

      m.getMemoryIO(ptr).putMemoryIO(m.getOffset(ptr), io);
    }
  @JRubyMethod(name = "putc", required = 1)
  @Override
  public IRubyObject putc(IRubyObject obj) {
    checkWritable();
    byte c = RubyNumeric.num2chr(obj);
    checkFrozen();

    data.internal.modify();
    ByteList bytes = data.internal.getByteList();
    if (data.modes.isAppendable()) {
      data.pos = bytes.length();
      bytes.append(c);
    } else {
      if (isEndOfString()) bytes.length((int) data.pos + 1);

      bytes.set((int) data.pos, c);
      data.pos++;
    }

    return obj;
  }
  @Override
  public IRubyObject each_byte(ThreadContext context, Block block) {
    checkReadable();
    Ruby runtime = context.runtime;
    ByteList bytes = data.internal.getByteList();

    // Check the length every iteration, since
    // the block can modify this string.
    while (data.pos < bytes.length()) {
      block.yield(context, runtime.newFixnum(bytes.get((int) data.pos++) & 0xFF));
    }
    return this;
  }
Beispiel #11
0
 public final void marshal(
     ThreadContext context, InvocationBuffer buffer, IRubyObject parameter) {
   if (parameter instanceof RubyString) {
     Util.checkStringSafety(context.getRuntime(), parameter);
     ByteList bl = ((RubyString) parameter).getByteList();
     buffer.putArray(
         bl.unsafeBytes(), bl.begin(), bl.length(), ArrayFlags.IN | ArrayFlags.NULTERMINATE);
   } else if (parameter.isNil()) {
     buffer.putAddress(0);
   } else {
     throw context.getRuntime().newArgumentError("Invalid string parameter");
   }
 }
Beispiel #12
0
  @JRubyMethod(name = "putc", required = 1)
  public IRubyObject putc(IRubyObject obj) {
    checkWritable();
    byte c = RubyNumeric.num2chr(obj);
    checkFrozen();

    internal.modify();
    ByteList bytes = internal.getByteList();
    if (modes.isAppendable()) {
      pos = bytes.length();
      bytes.append(c);
    } else {
      if (pos >= bytes.length()) {
        bytes.length((int) pos + 1);
      }

      bytes.set((int) pos, c);
      pos++;
    }

    return obj;
  }
Beispiel #13
0
  @JRubyMethod(name = "each_byte", frame = true)
  public IRubyObject each_byte(ThreadContext context, Block block) {
    checkReadable();
    Ruby runtime = context.getRuntime();
    ByteList bytes = internal.getByteList();

    // Check the length every iteration, since
    // the block can modify this string.
    while (pos < bytes.length()) {
      block.yield(context, runtime.newFixnum(bytes.get((int) pos++) & 0xFF));
    }
    return runtime.getNil();
  }
Beispiel #14
0
    public final void marshal(
        ThreadContext context, InvocationBuffer buffer, IRubyObject parameter) {
      if (parameter instanceof Buffer) {
        addBufferParameter(buffer, parameter, flags);
      } else if (parameter instanceof Pointer) {
        buffer.putAddress(getAddress((Pointer) parameter));
      } else if (parameter instanceof Struct) {
        IRubyObject memory = ((Struct) parameter).getMemory();
        if (memory instanceof Buffer) {
          addBufferParameter(buffer, memory, flags);
        } else if (memory instanceof Pointer) {
          buffer.putAddress(getAddress((Pointer) memory));
        } else if (memory == null || memory.isNil()) {
          buffer.putAddress(0L);
        } else {
          throw context.getRuntime().newArgumentError("Invalid Struct memory");
        }
      } else if (parameter.isNil()) {
        buffer.putAddress(0L);
      } else if (parameter instanceof RubyString) {
        ByteList bl = ((RubyString) parameter).getByteList();
        buffer.putArray(
            bl.getUnsafeBytes(), bl.begin(), bl.length(), flags | ArrayFlags.NULTERMINATE);

      } else if (parameter.respondsTo("to_ptr")) {
        final int MAXRECURSE = 4;
        for (int depth = 0; depth < MAXRECURSE; ++depth) {
          IRubyObject ptr = parameter.callMethod(context, "to_ptr");
          if (ptr instanceof Pointer) {
            buffer.putAddress(getAddress((Pointer) ptr));
          } else if (ptr instanceof Buffer) {
            addBufferParameter(buffer, ptr, flags);
          } else if (ptr.isNil()) {
            buffer.putAddress(0L);
          } else if (depth < MAXRECURSE && ptr.respondsTo("to_ptr")) {
            parameter = ptr;
            continue;
          } else {
            throw context.getRuntime().newArgumentError("to_ptr returned an invalid pointer");
          }
          break;
        }

      } else if (parameter instanceof RubyInteger && acceptIntegerValues) {

        buffer.putAddress(((RubyInteger) parameter).getLongValue());

      } else {
        throw context.getRuntime().newArgumentError("Invalid buffer/pointer parameter");
      }
    }
Beispiel #15
0
 public static final void checkStringSafety(Ruby runtime, IRubyObject value) {
   RubyString s = value.asString();
   if (runtime.getSafeLevel() > 0 && s.isTaint()) {
     throw runtime.newSecurityError("Unsafe string parameter");
   }
   ByteList bl = s.getByteList();
   final byte[] array = bl.unsafeBytes();
   final int end = bl.length();
   for (int i = bl.begin(); i < end; ++i) {
     if (array[i] == (byte) 0) {
       throw runtime.newSecurityError("string contains null byte");
     }
   }
 }
Beispiel #16
0
  private void ungetbyteCommon(int c) {
    ptr.string.modify();
    ptr.pos--;

    ByteList bytes = ptr.string.getByteList();

    if (isEndOfString()) bytes.length((int) ptr.pos + 1);

    if (ptr.pos == -1) {
      bytes.prepend((byte) c);
      ptr.pos = 0;
    } else {
      bytes.set((int) ptr.pos, c);
    }
  }
Beispiel #17
0
  @JRubyMethod(name = {"each_byte", "bytes"})
  public IRubyObject each_byte(ThreadContext context, Block block) {
    if (!block.isGiven()) return enumeratorize(context.runtime, this, "each_byte");

    checkReadable();
    Ruby runtime = context.runtime;
    ByteList bytes = ptr.string.getByteList();

    // Check the length every iteration, since
    // the block can modify this string.
    while (ptr.pos < bytes.length()) {
      block.yield(context, runtime.newFixnum(bytes.get((int) ptr.pos++) & 0xFF));
    }
    return this;
  }
Beispiel #18
0
  @JRubyMethod(name = "crc32", optional = 2, module = true, visibility = Visibility.PRIVATE)
  public static IRubyObject crc32(IRubyObject recv, IRubyObject[] args) throws Exception {
    args = Arity.scanArgs(recv.getRuntime(), args, 0, 2);
    long crc = 0;
    ByteList bytes = null;

    if (!args[0].isNil()) bytes = args[0].convertToString().getByteList();
    if (!args[1].isNil()) crc = RubyNumeric.num2long(args[1]);

    CRC32Ext ext = new CRC32Ext((int) crc);
    if (bytes != null) {
      ext.update(bytes.unsafeBytes(), bytes.begin(), bytes.length());
    }

    return recv.getRuntime().newFixnum(ext.getValue());
  }
Beispiel #19
0
 private IRubyObject internalSepGets(ByteList sep) throws IOException {
   ByteList result = new ByteList();
   int ce = io.read();
   while (ce != -1 && sep.indexOf(ce) == -1) {
     result.append((byte) ce);
     ce = io.read();
   }
   // io.available() only returns 0 after EOF is encountered
   // so we need to differentiate between the empty string and EOF
   if (0 == result.length() && -1 == ce) {
     return getRuntime().getNil();
   }
   line++;
   result.append(sep);
   return RubyString.newString(getRuntime(), result);
 }
Beispiel #20
0
  @JRubyMethod(name = "adler32", optional = 2, module = true, visibility = Visibility.PRIVATE)
  public static IRubyObject adler32(IRubyObject recv, IRubyObject[] args) throws Exception {
    args = Arity.scanArgs(recv.getRuntime(), args, 0, 2);
    int adler = 1;
    ByteList bytes = null;
    if (!args[0].isNil()) bytes = args[0].convertToString().getByteList();
    if (!args[1].isNil()) adler = RubyNumeric.fix2int(args[1]);

    Adler32Ext ext = new Adler32Ext(adler);
    if (bytes != null) {
      ext.update(
          bytes.unsafeBytes(),
          bytes.begin(),
          bytes.length()); // it's safe since adler.update doesn't modify the array
    }
    return recv.getRuntime().newFixnum(ext.getValue());
  }
Beispiel #21
0
    public void put(
        ThreadContext context,
        StructLayout.Storage cache,
        Member m,
        IRubyObject ptr,
        IRubyObject value) {

      if (isCharArray() && value instanceof RubyString) {
        ByteList bl = value.convertToString().getByteList();
        m.getMemoryIO(ptr)
            .putZeroTerminatedByteArray(
                m.offset,
                bl.getUnsafeBytes(),
                bl.begin(),
                Math.min(bl.length(), arrayType.length() - 1));

      } else if (false) {
        RubyArray ary = value.convertToArray();
        int count = ary.size();
        if (count > arrayType.length()) {
          throw context.getRuntime().newIndexError("array too big");
        }
        AbstractMemory memory = (AbstractMemory) ptr;

        // Clear any elements that will not be filled by the array
        if (count < arrayType.length()) {
          memory
              .getMemoryIO()
              .setMemory(
                  m.offset + (count * arrayType.getComponentType().getNativeSize()),
                  (arrayType.length() - count) * arrayType.getComponentType().getNativeSize(),
                  (byte) 0);
        }

        for (int i = 0; i < count; ++i) {
          op.put(
              context.getRuntime(),
              memory,
              m.offset + (i * arrayType.getComponentType().getNativeSize()),
              ary.entry(i));
        }
      } else {
        throw context.getRuntime().newNotImplementedError("cannot set array field");
      }
    }
Beispiel #22
0
  public static IRubyObject pack_sockaddr_un(ThreadContext context, IRubyObject filename) {
    ByteList str = filename.convertToString().getByteList();

    AddressFamily af = AddressFamily.AF_UNIX;
    int high = (af.intValue() & 0xff00) >> 8;
    int low = af.intValue() & 0xff;

    ByteList bl = new ByteList();
    bl.append((byte) high);
    bl.append((byte) low);
    bl.append(str);

    for (int i = str.length(); i < 104; i++) {
      bl.append((byte) 0);
    }

    return context.runtime.newString(bl);
  }
Beispiel #23
0
  private void ungetbyteCommon(RubyString ungetBytes) {
    ByteList ungetByteList = ungetBytes.getByteList();
    int len = ungetByteList.getRealSize();
    int start = ptr.pos;

    if (len == 0) return;

    ptr.string.modify();

    if (len > ptr.pos) {
      start = 0;
    } else {
      start = ptr.pos - len;
    }

    ByteList bytes = ptr.string.getByteList();

    if (isEndOfString()) bytes.length(Math.max(ptr.pos, len));

    bytes.replace(start, ptr.pos - start, ungetBytes.getByteList());

    ptr.pos = start;
  }
Beispiel #24
0
  /**
   * @throws IOException
   * @throws BadDescriptorException
   */
  private int bufferedWrite(ByteList buf) throws IOException, BadDescriptorException {
    checkWritable();
    ensureWrite();

    // Ruby ignores empty syswrites
    if (buf == null || buf.length() == 0) return 0;

    if (buf.length() > buffer.capacity()) { // Doesn't fit in buffer. Write immediately.
      flushWrite(); // ensure nothing left to write

      int n = descriptor.write(ByteBuffer.wrap(buf.getUnsafeBytes(), buf.begin(), buf.length()));
      if (n != buf.length()) {
        // TODO: check the return value here
      }
    } else {
      if (buf.length() > buffer.remaining()) flushWrite();

      buffer.put(buf.getUnsafeBytes(), buf.begin(), buf.length());
    }

    if (isSync()) flushWrite();

    return buf.getRealSize();
  }
Beispiel #25
0
  @Override
  public int parseString(RubyLexer lexer) throws java.io.IOException {
    ByteList str = null;
    ByteList eos = nd_lit;
    int len = nd_lit.length() - 1;
    boolean indent = (flags & STR_FUNC_INDENT) != 0;
    int c = lexer.nextc();

    if (c == EOF) return error(lexer, len, str, eos);

    // Found end marker for this heredoc
    if (lexer.was_bol() && lexer.whole_match_p(nd_lit, indent)) {
      lexer.heredoc_restore(this);
      return Tokens.tSTRING_END;
    }

    if ((flags & STR_FUNC_EXPAND) == 0) {
      do {
        ByteList lbuf = lexer.lex_lastline;
        int p = 0;
        int pend = lexer.lex_pend;
        if (pend > p) {
          switch (lexer.p(pend - 1)) {
            case '\n':
              pend--;
              if (pend == p || lexer.p(pend - 1) == '\r') {
                pend++;
                break;
              }
              break;
            case '\r':
              pend--;
              break;
          }
        }

        if (lexer.getHeredocIndent() > 0) {
          for (long i = 0; p + i < pend && lexer.update_heredoc_indent(lexer.p(p)); i++) {}
          lexer.setHeredocLineIndent(0);
        }

        if (str != null) {
          str.append(lbuf.makeShared(p, pend - p));
        } else {
          str = new ByteList(lbuf.makeShared(p, pend - p));
        }

        if (pend < lexer.lex_pend) str.append('\n');
        lexer.lex_goto_eol();

        if (lexer.getHeredocIndent() > 0) {
          lexer.setValue(str);
          return Tokens.tSTRING_CONTENT;
        }
        // MRI null checks str in this case but it is unconditionally non-null?
        if (lexer.nextc() == -1) return error(lexer, len, null, eos);
      } while (!lexer.whole_match_p(eos, indent));
    } else {
      ByteList tok = new ByteList();
      tok.setEncoding(lexer.getEncoding());
      if (c == '#') {
        switch (c = lexer.nextc()) {
          case '$':
          case '@':
            lexer.pushback(c);
            return Tokens.tSTRING_DVAR;
          case '{':
            lexer.commandStart = true;
            return Tokens.tSTRING_DBEG;
        }
        tok.append('#');
      }

      // MRI has extra pointer which makes our code look a little bit more strange in comparison
      do {
        lexer.pushback(c);

        Encoding enc[] = new Encoding[1];
        enc[0] = lexer.getEncoding();

        if ((c = new StringTerm(flags, '\0', '\n').parseStringIntoBuffer(lexer, tok, enc)) == EOF) {
          if (lexer.eofp) return error(lexer, len, str, eos);
          return restore(lexer);
        }
        if (c != '\n') {
          lexer.setValue(lexer.createStr(tok, 0));
          return Tokens.tSTRING_CONTENT;
        }
        tok.append(lexer.nextc());

        if (lexer.getHeredocIndent() > 0) {
          lexer.lex_goto_eol();
          lexer.setValue(lexer.createStr(tok, 0));
          return Tokens.tSTRING_CONTENT;
        }

        if ((c = lexer.nextc()) == EOF) return error(lexer, len, str, eos);
      } while (!lexer.whole_match_p(eos, indent));
      str = tok;
    }

    lexer.heredoc_restore(this);
    lexer.setStrTerm(new StringTerm(-1, '\0', '\0'));
    lexer.setValue(lexer.createStr(str, 0));
    return Tokens.tSTRING_CONTENT;
  }
Beispiel #26
0
  /**
   * @deprecated readall do busy loop for the IO which has NONBLOCK bit. You should implement the
   *     logic by yourself with fread().
   */
  @Deprecated
  public synchronized ByteList readall() throws IOException, BadDescriptorException {
    final long fileSize =
        descriptor.isSeekable() && descriptor.getChannel() instanceof FileChannel
            ? ((FileChannel) descriptor.getChannel()).size()
            : 0;
    //
    // Check file size - special files in /proc have zero size and need to be
    // handled by the generic read path.
    //
    if (fileSize > 0) {
      ensureRead();

      FileChannel channel = (FileChannel) descriptor.getChannel();
      final long left = fileSize - channel.position() + bufferedInputBytesRemaining();
      if (left <= 0) {
        eof = true;
        return null;
      }

      if (left > Integer.MAX_VALUE) {
        if (getRuntime() != null) {
          throw getRuntime().newIOError("File too large");
        } else {
          throw new IOException("File too large");
        }
      }

      ByteList result = new ByteList((int) left);
      ByteBuffer buf = ByteBuffer.wrap(result.getUnsafeBytes(), result.begin(), (int) left);

      //
      // Copy any buffered data (including ungetc byte)
      //
      copyBufferedBytes(buf);

      //
      // Now read unbuffered directly from the file
      //
      while (buf.hasRemaining()) {
        final int MAX_READ_CHUNK = 1 * 1024 * 1024;
        //
        // When reading into a heap buffer, the jvm allocates a temporary
        // direct ByteBuffer of the requested size.  To avoid allocating
        // a huge direct buffer when doing ludicrous reads (e.g. 1G or more)
        // we split the read up into chunks of no more than 1M
        //
        ByteBuffer tmp = buf.duplicate();
        if (tmp.remaining() > MAX_READ_CHUNK) {
          tmp.limit(tmp.position() + MAX_READ_CHUNK);
        }
        int n = channel.read(tmp);
        if (n <= 0) {
          break;
        }
        buf.position(tmp.position());
      }
      eof = true;
      result.length(buf.position());
      return result;
    } else if (descriptor.isNull()) {
      return new ByteList(0);
    } else {
      checkReadable();

      ByteList byteList = new ByteList();
      ByteList read = fread(BUFSIZE);

      if (read == null) {
        eof = true;
        return byteList;
      }

      while (read != null) {
        byteList.append(read);
        read = fread(BUFSIZE);
      }

      return byteList;
    }
  }
Beispiel #27
0
 protected boolean isEmpty(ByteList bytes) {
   return bytes.length() == 0;
 }
Beispiel #28
0
  @SuppressWarnings("fallthrough")
  @JRubyMethod(name = "read", optional = 2)
  public IRubyObject read(IRubyObject[] args) {
    checkReadable();

    ByteList buf = null;
    int length = 0;
    int oldLength = 0;
    RubyString originalString = null;

    switch (args.length) {
      case 2:
        originalString = args[1].convertToString();
        // must let original string know we're modifying, so shared buffers aren't damaged
        originalString.modify();
        buf = originalString.getByteList();
      case 1:
        if (!args[0].isNil()) {
          length = RubyNumeric.fix2int(args[0]);
          oldLength = length;

          if (length < 0) {
            throw getRuntime().newArgumentError("negative length " + length + " given");
          }
          if (length > 0 && pos >= internal.getByteList().length()) {
            eof = true;
            if (buf != null) buf.realSize = 0;
            return getRuntime().getNil();
          } else if (eof) {
            if (buf != null) buf.realSize = 0;
            return getRuntime().getNil();
          }
          break;
        }
      case 0:
        oldLength = -1;
        length = internal.getByteList().length();

        if (length <= pos) {
          eof = true;
          if (buf == null) {
            buf = new ByteList();
          } else {
            buf.realSize = 0;
          }

          return getRuntime().newString(buf);
        } else {
          length -= pos;
        }
        break;
      default:
        getRuntime().newArgumentError(args.length, 0);
    }

    if (buf == null) {
      int internalLength = internal.getByteList().length();

      if (internalLength > 0) {
        if (internalLength >= pos + length) {
          buf = new ByteList(internal.getByteList(), (int) pos, length);
        } else {
          int rest = (int) (internal.getByteList().length() - pos);

          if (length > rest) length = rest;
          buf = new ByteList(internal.getByteList(), (int) pos, length);
        }
      }
    } else {
      int rest = (int) (internal.getByteList().length() - pos);

      if (length > rest) length = rest;

      // Yow...this is still ugly
      byte[] target = buf.bytes;
      if (target.length > length) {
        System.arraycopy(internal.getByteList().bytes, (int) pos, target, 0, length);
        buf.begin = 0;
        buf.realSize = length;
      } else {
        target = new byte[length];
        System.arraycopy(internal.getByteList().bytes, (int) pos, target, 0, length);
        buf.begin = 0;
        buf.realSize = length;
        buf.bytes = target;
      }
    }

    if (buf == null) {
      if (!eof) buf = new ByteList();
      length = 0;
    } else {
      length = buf.length();
      pos += length;
    }

    if (oldLength < 0 || oldLength > length) eof = true;

    return originalString != null ? originalString : getRuntime().newString(buf);
  }
Beispiel #29
0
  // FIXME: We are assuming that original string will be raw bytes.  If -Ku is provided
  // this will not be true, but that is ok for now.  Deal with that when someone needs it.
  private IRubyObject _iconv(RubyString str, int start, int length) {
    if (fromEncoding == null) {
      throw getRuntime().newArgumentError("closed iconv");
    }

    ByteList bytes = str.getByteList();

    // treat start and end as start...end for end >= 0, start..end for end < 0
    if (start < 0) {
      start += bytes.length();
    }

    if (start < 0 || start > bytes.length()) { // invalid ranges result in an empty string
      return RubyString.newEmptyString(getRuntime());
    }

    if (length < 0 || length > bytes.length() - start) {
      length = bytes.length() - start;
    }

    ByteBuffer buf = ByteBuffer.wrap(bytes.getUnsafeBytes(), bytes.begin() + start, length);

    try {
      CharBuffer cbuf = fromEncoding.decode(buf);
      buf = toEncoding.encode(cbuf);
    } catch (MalformedInputException e) {
      throw getRuntime().newIllegalSequence(str.toString());
    } catch (UnmappableCharacterException e) {
      throw getRuntime().newIllegalSequence(str.toString());
    } catch (CharacterCodingException e) {
      throw getRuntime().newInvalidEncoding("invalid sequence");
    } catch (IllegalStateException e) {
      throw getRuntime().newIllegalSequence(str.toString());
    }
    byte[] arr = buf.array();

    start = 0;
    String displayName = toEncoding.charset().displayName();

    if (arr.length >= 2) { // minimum Byte Order Mark (BOM) length
      if (displayName.toLowerCase().startsWith("utf-16")) {
        if ((arr[0] == (byte) 0xfe && arr[1] == (byte) 0xff)) {
          if (count > 0) start = 2;
          endian = "BE";
        } else if (arr[0] == (byte) 0xff && arr[1] == (byte) 0xfe) {
          if (count > 0) start = 2;
          endian = "LE";
        }
      } else if (displayName.toLowerCase().startsWith("utf-32") && arr.length >= 4) {
        if (arr[0] == (byte) 0x00
            && arr[1] == (byte) 0x00
            && arr[2] == (byte) 0xfe
            && arr[3] == (byte) 0xff) {
          if (count > 0) start = 4;
          endian = "BE";
        } else if (arr[0] == (byte) 0xff
            && arr[1] == (byte) 0xfe
            && arr[2] == (byte) 0x00
            && arr[3] == (byte) 0x00) {
          if (count > 0) start = 4;
          endian = "LE";
        }
      }
    }

    count++;

    if (displayName.equalsIgnoreCase("utf-16") || displayName.equalsIgnoreCase("utf-32")) {
      displayName += endian;
    }

    ByteList r = new ByteList(arr, start, buf.limit() - start);

    EncodingDB.Entry entry = EncodingDB.getEncodings().get(displayName.getBytes());
    if (entry != null) {
      Encoding charset = entry.getEncoding();
      r.setEncoding(charset);
    }

    return getRuntime().newString(r);
  }
Beispiel #30
0
 @JRubyMethod(name = "write", required = 1)
 public IRubyObject write(IRubyObject p1) throws IOException {
   ByteList bytes = p1.convertToString().getByteList();
   io.write(bytes.unsafeBytes(), bytes.begin(), bytes.length());
   return getRuntime().newFixnum(bytes.length());
 }