001: /**
002: * @see com.coldcore.coloradoftp.filter.DataFilter
003: *
004: * TYPE A filter.
005: *
006: * Replaces on upload line feeds to platform default line feeds.
007: * On download this class does nothing.
008: *
009: * This class is capable of replacing Windows (#13#10) and Unix (#10) line feeds.
010: *
011: * WARNING! Buffer size property must match the buffer size used by a data connection,
012: * otherwise the performance will suffer.
013: */package com.coldcore.coloradoftp.filter.impl;
014:
015: import org.apache.log4j.Logger;
016:
017: import java.io.ByteArrayOutputStream;
018: import java.io.File;
019: import java.io.IOException;
020: import java.nio.ByteBuffer;
021: import java.nio.channels.Channels;
022: import java.nio.channels.WritableByteChannel;
023:
024: public class TypeADataFilter extends GenericDataFilter {
025:
026: private static Logger log = Logger.getLogger(TypeADataFilter.class);
027: protected boolean windows;
028: protected ByteArrayOutputStream bout;
029: protected WritableByteChannel twbc;
030: protected ByteBuffer rbuffer;
031: protected byte[] tarray;
032:
033: public TypeADataFilter() throws IOException {
034: windows = File.separator.equals("\\");
035:
036: bout = new ByteArrayOutputStream();
037: twbc = Channels.newChannel(bout);
038: }
039:
040: /** @deprecated Supports clients with v1.22 configuration files */
041: public TypeADataFilter(int bufferSize) throws IOException {
042: super ();
043: }
044:
045: /** Set type of OS and type of line feeds use (Windows or Unix)
046: * @param windows TRUE for Windows, FALSE for Unix
047: */
048: public void setWindows(boolean windows) {
049: this .windows = windows;
050: }
051:
052: public int read(ByteBuffer dst) throws IOException {
053: //Do not do anything until the destination buffer is clear, save extra efforts
054: if (dst.position() > 0 || dst.limit() != dst.capacity())
055: return 0;
056:
057: int rcap = dst.capacity() / 2;
058: if (rbuffer == null || rbuffer.capacity() > rcap) {
059: rbuffer = ByteBuffer.allocate(rcap);
060: rbuffer.flip();
061: }
062:
063: //Read data from the channel into the buffer and get it as a byte array
064: rbuffer.clear();
065: int read = rbc.read(rbuffer);
066: if (read < 1)
067: return read;
068: byte[] bytes = rbuffer.array();
069:
070: //Replace \n to \r\n
071: byte[] barr = new byte[read * 2];
072: byte b13 = (byte) 13;
073: int put = 0;
074: for (int z = 0; z < read; z++) {
075: byte b = bytes[z];
076: if (b == 13)
077: continue;
078: if (b == 10)
079: barr[put++] = b13;
080: barr[put++] = b;
081: }
082:
083: //Write the array with replaced line feeds into the destination buffer
084: dst.put(barr, 0, put);
085:
086: //Return how many bytes were put into the destination buffer
087: return barr.length;
088: }
089:
090: public int write(ByteBuffer src) throws IOException {
091:
092: int rcap = src.capacity() * 2;
093: if (rbuffer == null || rbuffer.capacity() > rcap) {
094: rbuffer = ByteBuffer.allocate(rcap);
095: rbuffer.flip();
096: }
097:
098: //Read data from the source into the buffer and get it as a byte array
099: rbuffer.clear();
100: int read = src.remaining();
101: rbuffer.put(src);
102: byte[] bytes = rbuffer.array();
103:
104: //Replace \n to \r\n or \r\n to \n
105: byte[] barr = new byte[read * 2];
106: byte b13 = (byte) 13;
107: int put = 0;
108: for (int z = 0; z < read; z++) {
109: byte b = bytes[z];
110: if (b == 13)
111: continue;
112: if (b == 10 && windows)
113: barr[put++] = b13;
114: barr[put++] = b;
115: }
116:
117: //Write the array with replaced line feeds into the buffer
118: rbuffer.clear();
119: rbuffer.put(barr, 0, put);
120: rbuffer.flip();
121:
122: //Forward the buffer to the underlying channel
123: int i = wbc.write(rbuffer);
124: if (i != put) {
125: //File will be damaged, cannot allow that
126: throw new RuntimeException(
127: "BUG: Data did not fit into channel");
128: }
129:
130: //Return how many bytes were read from the source buffer
131: return read;
132: }
133:
134: public boolean mayModifyDataLength() {
135: return true;
136: }
137: }
|