Skip to content

Commit

Permalink
Restore minimal part of old IO for jossl 0.9.5 to work.
Browse files Browse the repository at this point in the history
  • Loading branch information
headius committed Oct 15, 2014
1 parent 4dea67a commit 6884f63
Show file tree
Hide file tree
Showing 5 changed files with 3,105 additions and 1 deletion.
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/util/EmptyFileResource.java
Expand Up @@ -7,7 +7,7 @@

import java.nio.channels.Channel;

class EmptyFileResource implements FileResource {
public class EmptyFileResource implements FileResource {
// All empty resources are the same and immutable, so may as well
// cache the instance
private static final EmptyFileResource INSTANCE = new EmptyFileResource();
Expand Down
356 changes: 356 additions & 0 deletions core/src/main/java/org/jruby/util/io/CRLFStreamWrapper.java
@@ -0,0 +1,356 @@
package org.jruby.util.io;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channel;
import org.jcodings.Encoding;
import org.jcodings.specific.UTF16BEEncoding;
import org.jcodings.specific.UTF16LEEncoding;
import org.jruby.Ruby;
import org.jruby.platform.Platform;
import org.jruby.util.ByteList;

/**
* Wrapper around Stream that packs and unpacks LF <=> CRLF.
* @author nicksieger
*/
public class CRLFStreamWrapper implements Stream {
private final Stream stream;
private final boolean isWindows;
private boolean binmode = false;
private static final int CR = 13;
private static final int LF = 10;

public CRLFStreamWrapper(Stream stream) {
this.stream = stream;
// To differentiate between textmode and windows in how we handle crlf.
this.isWindows = Platform.IS_WINDOWS;
}

public ChannelDescriptor getDescriptor() {
return stream.getDescriptor();
}

public void clearerr() {
stream.clearerr();
}

@Override
public ByteBuffer getBuffer() {
return stream.getBuffer();
}

public ModeFlags getModes() {
return stream.getModes();
}

public void setModes(ModeFlags modes) {
stream.setModes(modes);
}

public boolean isSync() {
return stream.isSync();
}

public void setSync(boolean sync) {
stream.setSync(sync);
}

@Override
public int bufferedAvailable() {
return stream.bufferedAvailable();
}

public void setBinmode() {
binmode = true;
stream.setBinmode();
}

public boolean isBinmode() {
return binmode;
}

public boolean isAutoclose() {
return stream.isAutoclose();
}

public void setAutoclose(boolean autoclose) {
stream.setAutoclose(autoclose);
}

public ByteList fgets(ByteList separatorString) throws IOException, BadDescriptorException, EOFException {
return convertCRLFToLF(stream.fgets(separatorString));
}

public ByteList readall() throws IOException, BadDescriptorException, EOFException {
return convertCRLFToLF(stream.readall());
}

public int getline(ByteList dst, byte terminator) throws IOException, BadDescriptorException {
if (binmode) {
return stream.getline(dst, terminator);
}

ByteList intermediate = new ByteList();
int result = stream.getline(intermediate, terminator);
convertCRLFToLF(intermediate, dst);
return result;
}

public int getline(ByteList dst, byte terminator, long limit) throws IOException, BadDescriptorException {
if (binmode) {
return stream.getline(dst, terminator, limit);
}

ByteList intermediate = new ByteList();
int result = stream.getline(intermediate, terminator, limit);
convertCRLFToLF(intermediate, dst);
return result;
}

public ByteList fread(int number) throws IOException, BadDescriptorException, EOFException {
if (number == 0) {
if (stream.feof()) {
return null;
} else {
return new ByteList(0);
}
}
boolean eof = false;
ByteList bl = new ByteList(number > ChannelStream.BUFSIZE ? ChannelStream.BUFSIZE : number);
for (int i = 0; i < number; i++) {
int c = fgetc();
if (c == -1) {
eof = true;
break;
}
bl.append(c);
}
if (eof && bl.length() == 0) {
return null;
}
return bl;
}

public int fwrite(ByteList string) throws IOException, BadDescriptorException {
if (isWindows) return stream.fwrite(convertLFToCRLF(string));

return stream.fwrite(convertCRLFToLF(string));
}

public int fgetc() throws IOException, BadDescriptorException, EOFException {
int c = stream.fgetc();
if (!binmode && c == CR) {
c = stream.fgetc();
if (c != LF) {
stream.ungetc(c);
return CR;
}
}
return c;
}

public int ungetc(int c) {
return stream.ungetc(c);
}

public void fputc(int c) throws IOException, BadDescriptorException {
if (!binmode && c == LF) {
stream.fputc(CR);
}
stream.fputc(c);
}

public ByteList read(int number) throws IOException, BadDescriptorException, EOFException {
return convertCRLFToLF(stream.read(number));
}

public void fclose() throws IOException, BadDescriptorException {
stream.fclose();
}

public int fflush() throws IOException, BadDescriptorException {
return stream.fflush();
}

public void sync() throws IOException, BadDescriptorException {
stream.sync();
}

public boolean feof() throws IOException, BadDescriptorException {
return stream.feof();
}

public long fgetpos() throws IOException, PipeException, BadDescriptorException, InvalidValueException {
return stream.fgetpos();
}

public void lseek(long offset, int type) throws IOException, InvalidValueException, PipeException, BadDescriptorException {
stream.lseek(offset, type);
}

public void ftruncate(long newLength) throws IOException, PipeException, InvalidValueException, BadDescriptorException {
stream.ftruncate(newLength);
}

public int ready() throws IOException {
return stream.ready();
}

public void waitUntilReady() throws IOException, InterruptedException {
stream.waitUntilReady();
}

public boolean readDataBuffered() {
return stream.readDataBuffered();
}

public boolean writeDataBuffered() {
return stream.writeDataBuffered();
}

public InputStream newInputStream() {
return stream.newInputStream();
}

public OutputStream newOutputStream() {
return stream.newOutputStream();
}

public boolean isBlocking() {
return stream.isBlocking();
}

public void setBlocking(boolean blocking) throws IOException {
stream.setBlocking(blocking);
}

public void freopen(Ruby runtime, String path, ModeFlags modes) throws DirectoryAsFileException, IOException, InvalidValueException, PipeException, BadDescriptorException {
stream.freopen(runtime, path, modes);
}

private ByteList convertCRLFToLF(ByteList input) {
if (input == null || binmode) return input;

ByteList result = new ByteList();
convertCRLFToLF(input, result);
return result;
}

// FIXME: Horrific hack until we properly setup transcoding support of cr/lf logic in 1.9 proper. This class
// is going away in 9k and the LE/BE logic is never used by 1.8 support.

// I could not find any way in MRI to exercise this logic....endless needs
// binmode set (which obviously would not work here). Leaving it for now
// since I will likely be either doubling down on new knowledge for 1.7.2
// or ripping all this out when we have real transcoding logic ported
// properly
// private int skipCROfLF(ByteList src, int i, int c) {
// Encoding encoding = src.getEncoding();
// int length = src.length();
//
// if (encoding == UTF16BEEncoding.INSTANCE) {
// if (i + 3 < length && c == 0 && src.get(i + 1) == CR &&
// src.get(i + 2) == 0 && src.get(i + 3) == LF) {
// return i + 1;
// }
// } else if (encoding == UTF16LEEncoding.INSTANCE) {
// if (i + 3 < length && c == CR && src.get(i + 1) == 0 &&
// src.get(i + 2) == LF && src.get(i + 3) == 0) {
// return i + 1;
// }
// } else if (c == CR && i + 1 < length && src.get(i + 1) == LF) {
// return i;
// }
//
// return -1;
// }
//
// private void convertCRLFToLF(ByteList src, ByteList dst) {
// for (int i = 0; i < src.length(); i++) {
// int b = src.get(i);
// int j = skipCROfLF(src, i, b);
// if (j != -1) i = j;
//
// dst.append(b);
// }
// }


private void convertCRLFToLF(ByteList src, ByteList dst) {
for (int i = 0; i < src.length(); i++) {
int b = src.get(i);
if (b == CR && i + 1 < src.length() && src.get(i + 1) == LF) {
continue;
}
dst.append(b);
}
}

final byte[] CRBYTES = new byte[] { CR };
final byte[] CRLEBYTES = new byte[] { CR, 0};
final byte[] CRBEBYTES = new byte[] { 0, CR };

private byte[] crBytes(Encoding encoding) {
if (encoding == UTF16BEEncoding.INSTANCE) return CRBEBYTES;
if (encoding == UTF16LEEncoding.INSTANCE) return CRLEBYTES;

return CRBYTES;
}

final byte[] LFBYTES = new byte[] { LF };
final byte[] LFLEBYTES = new byte[] { LF, 0 };
final byte[] LFBEBYTES = new byte[] { 0, LF };

private byte[] lfBytes(Encoding encoding) {
if (encoding == UTF16BEEncoding.INSTANCE) return LFBEBYTES;
if (encoding == UTF16LEEncoding.INSTANCE) return LFLEBYTES;

return LFBYTES;
}

private ByteList convertLFToCRLF(ByteList bs) {
if (bs == null || binmode) return bs;

byte[] crBytes = crBytes(bs.getEncoding());
byte[] lfBytes = lfBytes(bs.getEncoding());

int p = bs.getBegin();
int end = p + bs.getRealSize();
byte[]bytes = bs.getUnsafeBytes();
Encoding enc = bs.getEncoding();

ByteList result = new ByteList();
int lastWrittenIndex = p;
while (p < end) {
int c = enc.mbcToCode(bytes, p, end);
int cLength = enc.codeToMbcLength(c);

if (c == LF) {
result.append(bytes, lastWrittenIndex, p - lastWrittenIndex);
result.append(crBytes);
result.append(lfBytes);
lastWrittenIndex = p + cLength;
}

p += cLength;
}

if (lastWrittenIndex < end) {
result.append(bytes, lastWrittenIndex, end - lastWrittenIndex);
}

return result;
}

public Channel getChannel() {
return stream.getChannel();
}

public final int refillBuffer() throws IOException {
return stream.refillBuffer();
}
}

0 comments on commit 6884f63

Please sign in to comment.