/*
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

package com.facebook.imagepipeline.producers;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Executor;

import android.net.Uri;
import android.util.Base64;

import com.facebook.common.internal.Preconditions;
import com.facebook.common.internal.VisibleForTesting;
import com.facebook.imagepipeline.memory.PooledByteBufferFactory;
import com.facebook.imagepipeline.request.ImageRequest;

/**
 * Producer for data URIs.
 *
 * <p>Data URIs embed the data in the URI itself. They don't point to a file location;
 * the URI is the data. Data can be encoded in either base-64 or escaped ASCII.
 * See the <a href="http://tools.ietf.org/html/rfc2397">spec</a> for full details.
 *
 * <p>Data URIs are intended for small pieces of data only, since the URI lives on the Java
 * heap. For large data, use a another URI type.
 *
 * <p>Charsets specified in the URI are ignored. Only UTF-8 encoding is currently supported.
 */
public class DataFetchProducer extends LocalFetchProducer {

  private static final String PRODUCER_NAME = "DataFetchProducer";

  public DataFetchProducer(
      Executor executor,
      PooledByteBufferFactory pooledByteBufferFactory) {
    super(executor, pooledByteBufferFactory);
  }

  @Override
  protected InputStream getInputStream(ImageRequest imageRequest) throws IOException {
    return new ByteArrayInputStream(getData(imageRequest.getSourceUri().toString()));
  }

  @Override
  protected int getLength(ImageRequest imageRequest) {
    return getData(imageRequest.getSourceUri().toString()).length;
  }

  @Override
  protected String getProducerName() {
    return PRODUCER_NAME;
  }

  @VisibleForTesting
  static byte[] getData(String uri) {
    /*
     * Format of a data URL:
     * data:mime/type;param=value;param=value;base64,actual_data
     * everything is optional except the actual data, which is either
     * base-64 or escaped ASCII encoded.
     */
    Preconditions.checkArgument(uri.substring(0, 5).equals("data:"));
    int commaPos = uri.indexOf(',');

    String dataStr = uri.substring(commaPos + 1, uri.length());
    if (isBase64(uri.substring(0, commaPos))) {
      return Base64.decode(dataStr, Base64.DEFAULT);
    } else {
      String str = Uri.decode(dataStr);
      byte[] b = str.getBytes();
      return b;
    }
  }

  @VisibleForTesting
  static boolean isBase64(String prefix) {
    if (!prefix.contains(";")) {
      return false;
    }
    String[] parameters = prefix.split(";");
    return parameters[parameters.length - 1].equals("base64");
  }
}

Add support for data URIs in [Part 1]
Add support for data URIs in [Part 1]
