package info.guardianproject.iocipher.camera.io; /** * * This file contains code from the IOCipher Camera Library "CipherCam". * * For more information about IOCipher, see https://guardianproject.info/code/iocipher * and this sample library: https://github.com/n8fr8/IOCipherCameraExample * * IOCipher Camera Sample is distributed under this license (aka the 3-clause BSD license) * * Some of this class was originally part of JCodec ( www.jcodec.org ) This software is distributed * under FreeBSD License * * @author n8fr8, The JCodec project * */ // inspired by https://github.com/commonsguy/cw-omnibus/tree/master/ContentProvider/Pipe import info.guardianproject.iocipher.File; import info.guardianproject.iocipher.FileInputStream; import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.UUID; import android.content.ContentProvider; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor.AutoCloseOutputStream; import android.util.Log; import android.webkit.MimeTypeMap; public class IOCipherContentProvider extends ContentProvider { public static final String TAG = "IOCipherContentProvider"; public static final String DEFAULT_AUTHORITY = "info.guardianproject.iocipher.camera"; private MimeTypeMap mimeTypeMap; private static HashMap<String,String> keyToPathMap = new HashMap<String,String>(); @Override public boolean onCreate() { mimeTypeMap = MimeTypeMap.getSingleton(); return true; } /* * Before something can be accessed by the content provider, it must be added to this map. * This protects from any app being able to query the IOCipher store at will */ public static String addShare (String path, String authority) { String uuid = UUID.randomUUID().toString().substring(0,8) + '-' + new File(path).getName(); keyToPathMap.put(uuid, path); return "content://" + authority + '/' + uuid; } @Override public String getType(Uri uri) { String fileExtension = MimeTypeMap.getFileExtensionFromUrl(uri.toString()); String type = mimeTypeMap.getMimeTypeFromExtension(fileExtension); return type; } @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { ParcelFileDescriptor[] pipe = null; InputStream in = null; String pathKey = uri.getPath(); if (pathKey.startsWith("/")); pathKey = pathKey.substring(1); String pathReal = keyToPathMap.get(pathKey); try { File fileShare = new File(pathReal); pipe = ParcelFileDescriptor.createPipe(); in = new FileInputStream(fileShare); new PipeFeederThread(in, new AutoCloseOutputStream(pipe[1]) { } ).start(); } catch (IOException e) { Log.e(TAG, "Error opening pipe", e); throw new FileNotFoundException("Could not open pipe for: " + uri.toString()); } return (pipe[0]); } @Override public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) { //Log.d(TAG,"query called: " + url.toString()); //throw new RuntimeException("Operation not supported"); return null; } @Override public Uri insert(Uri uri, ContentValues initialValues) { throw new RuntimeException("Operation not supported"); } @Override public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { throw new RuntimeException("Operation not supported"); } @Override public int delete(Uri uri, String where, String[] whereArgs) { throw new RuntimeException("Operation not supported"); } static class PipeFeederThread extends Thread { InputStream in; BufferedOutputStream out; PipeFeederThread(InputStream in, OutputStream out) { this.in = in; this.out = new BufferedOutputStream(out, 32000); setDaemon(true); } @Override public void run() { byte[] buf = new byte[4096]; int len; try { int idx = 0; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); idx+=buf.length; // Log.d(TAG,"writing video at " + idx); } in.close(); out.flush(); out.close(); } catch (IOException e) { Log.e(TAG, "File transfer failed:", e); } } } }