All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.robovm.libimobiledevice.IDeviceConnection Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2013 RoboVM AB
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.robovm.libimobiledevice;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.robovm.libimobiledevice.binding.IDeviceConnectionRef;
import org.robovm.libimobiledevice.binding.IDeviceError;
import org.robovm.libimobiledevice.binding.IntOut;
import org.robovm.libimobiledevice.binding.LibIMobileDevice;

/**
 * Represents a device connection.
 */
public class IDeviceConnection implements AutoCloseable {
    protected IDeviceConnectionRef ref;
    private DeviceInputStream deviceInputStream;
    private DeviceOutputStream deviceOutputStream;

    IDeviceConnection(IDeviceConnectionRef ref) {
        this.ref = ref;
    }
    
    protected IDeviceConnectionRef getRef() {
        checkDisposed();
        return ref;
    }

    private void createStreams() {
        if (deviceInputStream == null) {
            deviceInputStream = new DeviceInputStream();
            deviceOutputStream = new DeviceOutputStream();
        }
    }

    /**
     * Returns an {@link InputStream} for reading from this
     * {@link IDeviceConnection}.
     */
    public InputStream getInputStream() {
        createStreams();
        return deviceInputStream;
    }

    /**
     * Returns and {@link OutputStream} for writing to this
     * {@link IDeviceConnection}.
     */
    public OutputStream getOutputStream() {
        createStreams();
        return deviceOutputStream;
    }

    /**
     * Receives data from the device. Waits indefinitely for data on the
     * connection.
     *
     * @param buffer the byte array in which to store the received data.
     * @param offset the initial position in {@code buffer} to store the 
     *               received bytes.
     * @param count the maximum number of bytes to store in {@code buffer}.
     * @return the number of bytes received.
     */
    public int receive(byte[] buffer, int offset, int count) {
        return receive(buffer, offset, count, Integer.MAX_VALUE);
    }
    
    /**
     * Receives data from the device. Returns after the given timeout even if no 
     * data has been received.
     *
     * @param buffer the byte array in which to store the received data.
     * @param offset the initial position in {@code buffer} to store the 
     *               received bytes.
     * @param count the maximum number of bytes to store in {@code buffer}.
     * @param timeout timeout in milliseconds after which this method will
     *                return even if no data has been received.
     * @return the number of bytes received.
     */
    public int receive(byte[] buffer, int offset, int count, int timeout) {
        checkArrayBounds(buffer, offset, count);
        
        if (count == 0) {
            return 0;
        }
        
        byte[] data = buffer;
        if (offset > 0) {
            data = new byte[count];
        }
        
        IntOut bytesReceivedOut = new IntOut();
        try {
            IDevice.checkResult(LibIMobileDevice.idevice_connection_receive_timeout(getRef(), 
                    data, count, bytesReceivedOut, timeout),  IDeviceError.IDEVICE_E_TIMEOUT);
            int bytesRead = bytesReceivedOut.getValue();
            if (bytesRead > 0 && data != buffer) {
                System.arraycopy(data, 0, buffer, offset, bytesRead);
            }
            return bytesRead;
        } finally {
            bytesReceivedOut.delete();
        }
    }

    private void checkArrayBounds(byte[] buffer, int offset, int count) {
        if ((offset | count) < 0 || offset > buffer.length || buffer.length - offset < count) {
            throw new ArrayIndexOutOfBoundsException("length=" + buffer.length 
                    + "; regionStart=" + offset + "; regionLength=" + count);
        }
    }
    
    /**
     * Sends data to the device on this connection.
     *
     * @param buffer the buffer to be sent.
     * @param offset the start position in {@code buffer} from where to get bytes.
     * @param count the number of bytes from {@code buffer} to send.
     * @return the number of bytes actually sent.
     */
    public int send(byte[] buffer, int offset, int count) {
        checkArrayBounds(buffer, offset, count);
        
        if (count == 0) {
            return 0;
        }
        
        byte[] data = buffer;
        if (offset > 0) {
            data = new byte[count];
            System.arraycopy(buffer, offset, data, 0, count);
        }
        
        IntOut bytesSentOut = new IntOut();
        try {
            IDevice.checkResult(LibIMobileDevice.idevice_connection_send(getRef(), data, count, bytesSentOut));
            return bytesSentOut.getValue();
        } finally {
            bytesSentOut.delete();
        }
    }
    
    /**
     * Disconnects from the device. This is the same as calling {@link #dispose()}
     * or {@link #close()}.
     */
    public void disconnect() {
        dispose();
    }
    
    protected final void checkDisposed() {
        if (ref == null) {
            throw new LibIMobileDeviceException("Already disposed");
        }
    }
    
    public synchronized void dispose() {
        checkDisposed();
        LibIMobileDevice.idevice_disconnect(ref);
        ref = null;
    }
    
    @Override
    public void close() {
        dispose();
    }

    private class DeviceInputStream extends InputStream {

        @Override
        public int read() throws IOException {
            byte[] b = new byte[1];
            int n = read(b);
            return n <= 0 ? -1 : b[0] & 0xff;
        }

        @Override
        public int read(byte[] b) throws IOException {
            return read(b, 0, b.length);
        }

        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            try {
                return receive(b, off, len);
            } catch (LibIMobileDeviceException e) {
                throw new IOException(e);
            }
        }
    }

    private class DeviceOutputStream extends OutputStream {

        @Override
        public void write(int b) throws IOException {
            byte[] buffer = new byte[1];
            buffer[0] = (byte) b;
            write(buffer);
        }

        @Override
        public void write(byte[] b) throws IOException {
            write(b, 0, b.length);
        }

        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            checkArrayBounds(b, off, len);
            try {
                send(b, off, len);
            } catch (LibIMobileDeviceException e) {
                throw new IOException(e);
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy