MultipartBody.java

/*
 * Decompiled with CFR 0_132.
 * 
 * Could not load the following classes:
 *  android.text.TextUtils
 */
package org.xutils.http.body;

import android.text.TextUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.xutils.common.Callback;
import org.xutils.common.util.IOUtil;
import org.xutils.common.util.KeyValue;
import org.xutils.http.ProgressHandler;
import org.xutils.http.body.BodyItemWrapper;
import org.xutils.http.body.FileBody;
import org.xutils.http.body.InputStreamBody;
import org.xutils.http.body.ProgressBody;

public class MultipartBody
implements ProgressBody {
    private static byte[] BOUNDARY_PREFIX_BYTES = "--------7da3d81520810".getBytes();
    private static byte[] END_BYTES = "\r\n".getBytes();
    private static byte[] TWO_DASHES_BYTES = "--".getBytes();
    private byte[] boundaryPostfixBytes;
    private String contentType;
    private String charset = "UTF-8";
    private List<KeyValue> multipartParams;
    private long total = 0L;
    private long current = 0L;
    private ProgressHandler callBackHandler;

    public MultipartBody(List<KeyValue> multipartParams, String charset) {
        if (!TextUtils.isEmpty((CharSequence)charset)) {
            this.charset = charset;
        }
        this.multipartParams = multipartParams;
        this.generateContentType();
        CounterOutputStream counter = new CounterOutputStream();
        try {
            this.writeTo(counter);
            this.total = counter.total.get();
        }
        catch (IOException e) {
            this.total = -1L;
        }
    }

    @Override
    public void setProgressHandler(ProgressHandler progressHandler) {
        this.callBackHandler = progressHandler;
    }

    private void generateContentType() {
        String boundaryPostfix = Double.toHexString(Math.random() * 65535.0);
        this.boundaryPostfixBytes = boundaryPostfix.getBytes();
        this.contentType = "multipart/form-data; boundary=" + new String(BOUNDARY_PREFIX_BYTES) + boundaryPostfix;
    }

    @Override
    public long getContentLength() {
        return this.total;
    }

    @Override
    public void setContentType(String subType) {
        int index = this.contentType.indexOf(";");
        this.contentType = "multipart/" + subType + this.contentType.substring(index);
    }

    @Override
    public String getContentType() {
        return this.contentType;
    }

    @Override
    public void writeTo(OutputStream out) throws IOException {
        if (this.callBackHandler != null && !this.callBackHandler.updateProgress(this.total, this.current, true)) {
            throw new Callback.CancelledException("upload stopped!");
        }
        for (KeyValue kv : this.multipartParams) {
            String name = kv.key;
            Object value = kv.value;
            if (TextUtils.isEmpty((CharSequence)name) || value == null) continue;
            this.writeEntry(out, name, value);
        }
        this.writeLine(out, TWO_DASHES_BYTES, BOUNDARY_PREFIX_BYTES, this.boundaryPostfixBytes, TWO_DASHES_BYTES);
        out.flush();
        if (this.callBackHandler != null) {
            this.callBackHandler.updateProgress(this.total, this.total, true);
        }
    }

    private void writeEntry(OutputStream out, String name, Object value) throws IOException {
        this.writeLine(out, TWO_DASHES_BYTES, BOUNDARY_PREFIX_BYTES, this.boundaryPostfixBytes);
        String fileName = "";
        String contentType = null;
        if (value instanceof BodyItemWrapper) {
            BodyItemWrapper wrapper = (BodyItemWrapper)value;
            value = wrapper.getValue();
            fileName = wrapper.getFileName();
            contentType = wrapper.getContentType();
        }
        if (value instanceof File) {
            File file = (File)value;
            if (TextUtils.isEmpty((CharSequence)fileName)) {
                fileName = file.getName();
            }
            if (TextUtils.isEmpty(contentType)) {
                contentType = FileBody.getFileContentType(file);
            }
            this.writeLine(out, new byte[][]{MultipartBody.buildContentDisposition(name, fileName, this.charset)});
            this.writeLine(out, new byte[][]{MultipartBody.buildContentType(value, contentType, this.charset)});
            this.writeLine(out, new byte[0][]);
            this.writeFile(out, file);
            this.writeLine(out, new byte[0][]);
        } else {
            this.writeLine(out, new byte[][]{MultipartBody.buildContentDisposition(name, fileName, this.charset)});
            this.writeLine(out, new byte[][]{MultipartBody.buildContentType(value, contentType, this.charset)});
            this.writeLine(out, new byte[0][]);
            if (value instanceof InputStream) {
                this.writeStreamAndCloseIn(out, (InputStream)value);
                this.writeLine(out, new byte[0][]);
            } else {
                byte[] content = value instanceof byte[] ? (byte[])value : String.valueOf(value).getBytes(this.charset);
                this.writeLine(out, new byte[][]{content});
                this.current += (long)content.length;
                if (this.callBackHandler != null && !this.callBackHandler.updateProgress(this.total, this.current, false)) {
                    throw new Callback.CancelledException("upload stopped!");
                }
            }
        }
    }

    private /* varargs */ void writeLine(OutputStream out, byte[] ... bs) throws IOException {
        if (bs != null) {
            for (byte[] b : bs) {
                out.write(b);
            }
        }
        out.write(END_BYTES);
    }

    private void writeFile(OutputStream out, File file) throws IOException {
        if (out instanceof CounterOutputStream) {
            ((CounterOutputStream)out).addFile(file);
        } else {
            this.writeStreamAndCloseIn(out, new FileInputStream(file));
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void writeStreamAndCloseIn(OutputStream out, InputStream in) throws IOException {
        if (out instanceof CounterOutputStream) {
            ((CounterOutputStream)out).addStream(in);
        } else {
            try {
                int len;
                byte[] buf = new byte[1024];
                while ((len = in.read(buf)) >= 0) {
                    out.write(buf, 0, len);
                    this.current += (long)len;
                    if (this.callBackHandler == null || this.callBackHandler.updateProgress(this.total, this.current, false)) continue;
                    throw new Callback.CancelledException("upload stopped!");
                }
            }
            finally {
                IOUtil.closeQuietly(in);
            }
        }
    }

    private static byte[] buildContentDisposition(String name, String fileName, String charset) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder("Content-Disposition: form-data");
        result.append("; name=\"").append(name.replace("\"", "\\\"")).append("\"");
        if (!TextUtils.isEmpty((CharSequence)fileName)) {
            result.append("; filename=\"").append(fileName.replace("\"", "\\\"")).append("\"");
        }
        return result.toString().getBytes(charset);
    }

    private static byte[] buildContentType(Object value, String contentType, String charset) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder("Content-Type: ");
        contentType = TextUtils.isEmpty((CharSequence)contentType) ? (value instanceof String ? "text/plain; charset=" + charset : "application/octet-stream") : contentType.replaceFirst("\\/jpg$", "/jpeg");
        result.append(contentType);
        return result.toString().getBytes(charset);
    }

    private class CounterOutputStream
    extends OutputStream {
        final AtomicLong total = new AtomicLong(0L);

        public void addFile(File file) {
            if (this.total.get() == -1L) {
                return;
            }
            this.total.addAndGet(file.length());
        }

        public void addStream(InputStream inputStream) {
            if (this.total.get() == -1L) {
                return;
            }
            long length = InputStreamBody.getInputStreamLength(inputStream);
            if (length > 0L) {
                this.total.addAndGet(length);
            } else {
                this.total.set(-1L);
            }
        }

        @Override
        public void write(int oneByte) throws IOException {
            if (this.total.get() == -1L) {
                return;
            }
            this.total.incrementAndGet();
        }

        @Override
        public void write(byte[] buffer) throws IOException {
            if (this.total.get() == -1L) {
                return;
            }
            this.total.addAndGet(buffer.length);
        }

        @Override
        public void write(byte[] buffer, int offset, int count) throws IOException {
            if (this.total.get() == -1L) {
                return;
            }
            this.total.addAndGet(count);
        }
    }

}