air/extension/com/phonegap/file/filemanager.java
air/extension/com/phonegap/file/filemanager.java
Back to zip file contents
      /*
 * PhoneGap is available under *either* the terms of the modified BSD license *or* the
 * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
 * 
 * Copyright (c) 2005-2010, Nitobi
 * Copyright (c) 2010, IBM Corporation
 */ 
package com.phonegap.file;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;

import net.rim.device.api.io.Base64OutputStream;
import net.rim.device.api.io.FileNotFoundException;
import net.rim.device.api.io.MIMETypeAssociations;

import org.json.me.JSONArray;
import org.json.me.JSONException;

import com.phonegap.api.Plugin;
import com.phonegap.api.PluginResult;
import com.phonegap.util.Logger;

public class FileManager extends Plugin {

    /**
     * File related errors.
     */
    public static int NOT_FOUND_ERR = 1;
    public static int SECURITY_ERR = 2;
    public static int ABORT_ERR = 3;
    public static int NOT_READABLE_ERR = 4;
    public static int ENCODING_ERR = 5;
    public static int NO_MODIFICATION_ALLOWED_ERR = 6;
    public static int INVALID_STATE_ERR = 7;
    public static int SYNTAX_ERR = 8;
    public static int INVALID_MODIFICATION_ERR = 9;
    public static int QUOTA_EXCEEDED_ERR = 10;
    public static int TYPE_MISMATCH_ERR = 11;
    public static int PATH_EXISTS_ERR = 12;

    /**
     * Possible actions.
     */
    protected static final int ACTION_READ_AS_TEXT = 0;
    protected static final int ACTION_READ_AS_DATA_URL = 1;
    protected static final int ACTION_WRITE = 2;
    protected static final int ACTION_TRUNCATE = 3;
    
    public PluginResult execute(String action, JSONArray args, String callbackId) {

        // get parameters
        String filePath = null;
        try {
            filePath = args.getString(0);
        } catch (JSONException e) {
            Logger.log(this.getClass().getName() + ": " + e);
            return new PluginResult(PluginResult.Status.JSONEXCEPTION, 
                    "Invalid or missing file parameter");
        }
        
        // perform specified action
        int a = getAction(action);
        if (a == ACTION_READ_AS_TEXT) {
            String result = null;
            try {
                result = readAsText(filePath, args.optString(1));
            } catch (FileNotFoundException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(NOT_FOUND_ERR));
            } catch (UnsupportedEncodingException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(ENCODING_ERR));
            } catch (IOException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(NOT_READABLE_ERR));            
            }
            return new PluginResult(PluginResult.Status.OK, result);
        }
        else if (a == ACTION_READ_AS_DATA_URL) {
            String result = null;
            try {
                result = readAsDataURL(filePath);
            } catch (FileNotFoundException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(NOT_FOUND_ERR));
            } catch (UnsupportedEncodingException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(ENCODING_ERR));
            } catch (IOException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(NOT_READABLE_ERR));            
            }
            return new PluginResult(PluginResult.Status.OK, result);
        }
        else if (a == ACTION_WRITE) {
            int bytesWritten = 0;
            try {
                // write file data
                int position = Integer.parseInt(args.optString(2));
                bytesWritten = writeFile(filePath, args.getString(1), position);
            } catch (JSONException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.JSONEXCEPTION, 
                        "File data could not be retrieved.");
            } catch (IOException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(NO_MODIFICATION_ALLOWED_ERR));
            } catch (NumberFormatException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.ILLEGAL_ARGUMENT_EXCEPTION, 
                        Integer.toString(SYNTAX_ERR));                
            }
            return new PluginResult(PluginResult.Status.OK, bytesWritten);
        }
        else if (a == ACTION_TRUNCATE) {
            long fileSize = 0;
            try {
                // retrieve new file size
                long size = Long.parseLong(args.getString(1));
                fileSize = truncateFile(filePath, size);
            } catch (JSONException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.JSONEXCEPTION, 
                        "File size must be a number.");
            } catch (FileNotFoundException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(NOT_FOUND_ERR));
            } catch (IOException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.IOEXCEPTION, 
                        Integer.toString(NO_MODIFICATION_ALLOWED_ERR));
            } catch (NumberFormatException e) {
                Logger.log(this.getClass().getName() + ": " + e);
                return new PluginResult(PluginResult.Status.ILLEGAL_ARGUMENT_EXCEPTION, 
                        Integer.toString(SYNTAX_ERR));                
            }
            return new PluginResult(PluginResult.Status.OK, fileSize);
        }

        // invalid action
        return new PluginResult(PluginResult.Status.INVALIDACTION, 
                "File: invalid action " + action);
    }
    
    /**
     * Reads a file and encodes the contents using the specified encoding.
     * @param filePath  Full path of the file to be read
     * @param encoding  Encoding to use for the file contents
     * @return String containing encoded file contents
     */
    protected String readAsText(String filePath, String encoding) throws FileNotFoundException, UnsupportedEncodingException, IOException {
        // read the file
        byte[] blob = FileUtils.readFile(filePath, Connector.READ);
        
        // return encoded file contents
        Logger.log(this.getClass().getName() + ": encoding file contents using " + encoding);
        return new String(blob, encoding);
    }
    
    /**
     * Read file and return data as a base64 encoded data url.
     * A data url is of the form:
     *      data:[][;base64],
     * @param filePath  Full path of the file to be read
     */
    protected String readAsDataURL(String filePath) throws FileNotFoundException, IOException {
        String result = null;

        // read file
        byte[] blob = FileUtils.readFile(filePath, Connector.READ);
        
        // encode file contents using BASE64 encoding
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        Base64OutputStream base64OutputStream = new Base64OutputStream(byteArrayOutputStream);
        base64OutputStream.write(blob);
        base64OutputStream.flush();
        base64OutputStream.close(); 
        result = byteArrayOutputStream.toString();
 
        // put result in proper form 
        String mediaType = MIMETypeAssociations.getMIMEType(filePath);
        if (mediaType == null) {
            mediaType = "";
        }
        result = "data:" + mediaType + ";base64," + result;            
        
        return result;
    }
    
    /**
     * Reads file as byte array.
     * @param filePath      Full path of the file to be read  
     * @return file content as a byte array
     */
    protected byte[] readFile(String filePath) throws FileNotFoundException, IOException {
        return FileUtils.readFile(filePath, Connector.READ);
    }

    /**
     * Writes data to the specified file.
     * @param filePath  Full path of file to be written to
     * @param data      Data to be written
     * @param position  Position at which to begin writing
     */
    protected int writeFile(String filePath, String data, int position) throws IOException {
        return FileUtils.writeFile(filePath, data.getBytes(), position);
    }
    
    /**
     * Changes the length of the specified file.  If shortening, data beyond new length
     * is discarded. 
     * @param fileName  The full path of the file to truncate
     * @param size      The size to which the length of the file is to be adjusted
     * @param the size of the file
     */
    protected long truncateFile(String filePath, long size) throws FileNotFoundException, IOException {
        long fileSize = 0;
        FileConnection fconn = null;
        try {
            fconn = (FileConnection)Connector.open(filePath, Connector.READ_WRITE);
            if (!fconn.exists()) {
                throw new FileNotFoundException(filePath + " not found");                
            }
            if (size >= 0) {
                fconn.truncate(size);
            }
            fileSize = fconn.fileSize();
        } finally {
            try {
                if (fconn != null) fconn.close();
            } catch (IOException e) {
                Logger.log(this.getClass().getName() + ": " + e);
            }
        }
        return fileSize;
    }
    
    /**
     * Returns action to perform.
     * @param action 
     * @return action to perform
     */
    protected static int getAction(String action) {
        if ("readAsText".equals(action)) return ACTION_READ_AS_TEXT;
        if ("readAsDataURL".equals(action)) return ACTION_READ_AS_DATA_URL;
        if ("write".equals(action)) return ACTION_WRITE;
        if ("truncate".equals(action)) return ACTION_TRUNCATE;
        return -1;
    }   
}