Android Open Source - itude-mobile-android-util Data Util






From Project

Back to project page itude-mobile-android-util.

License

The source code is released under:

Apache License

If you think the Android project itude-mobile-android-util listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * (C) Copyright Itude Mobile B.V., The Netherlands
 * //from  w ww  . jav a  2s  .  co  m
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.itude.mobile.android.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

import org.apache.commons.codec.binary.Base64;

import android.content.Context;

import com.itude.mobile.android.util.log.MBLog;

/**
 * Utility class for methods to handle data.
 */
public final class DataUtil
{
  private static final String       TAG               = "DataUtil";

  private static DataUtil           _instance;
  private Context                   _context;

  private final Map<String, Reader> _filenameToReader = new HashMap<String, Reader>();
  private final Reader              _readerNone       = new ReadFromNone();
  private final ReadFromAll         _readerAll        = new ReadFromAll();

  /**
   * Default constructor
   */
  private DataUtil()
  {
  }

  /**
   * @return {@link DataUtil}
   */
  public static DataUtil getInstance()
  {
    if (_instance == null)
    {
      _instance = new DataUtil();
    }

    return _instance;
  }

  /**
   * Set the {@link Context} for this instance
   * 
   * @param context {@link Context}
   */
  public void setContext(Context context)
  {
    _context = context;
    AssetUtil.getInstance().setContext(_context);
    FileUtil.getInstance().setContext(_context);
  }

  /**
   * Should be called after someone creates a file otherwise
   * the file will not be seen by  {@link #readFromAssetOrFile(String)}.
   * Currently called automatically by {@link FileUtil#writeObjectToFile(Object, String)}
   * and {@link FileUtil#writeToFile(byte[], String, String)}.
   *
   * @param filename file name
   */
  public void clearReaderCachForFile(String filename)
  {
    _filenameToReader.remove(filename);
  }

  /**
   * Get the byte array from an asset or file.
   * 
   * @param filename file name
   * @return byte array
   */
  public byte[] readFromAssetOrFile(String filename)
  {
    if (_filenameToReader.containsKey(filename))
    {
      // we have previously read this file, so use the correct reader directly.
      Reader readerForThisFile = _filenameToReader.get(filename);
      return readerForThisFile.read(filename);
    }
    else
    {
      // first time we try to read this file, try all readers
      TwinResult<byte[], Reader> result = _readerAll.read(filename);
      if (result._mainResult == null)
      {
        // in future we just dont try for this file anymore
        _filenameToReader.put(filename, _readerNone);
        // and only the first time we give a message
        String message = "DataUtil.readFromAssetOrFile: unable to read file or asset data from file with name " + filename;
        MBLog.i(TAG, message);
      }
      else
      {
        // in future immediately use the correct reader for this filename
        _filenameToReader.put(filename, result._secondResult);
      }
      return result._mainResult;
    }
  }

  /**
   * Compress byte array 
   * 
   * @param uncompressed byte array
   * @return compressed byte array
   */
  public byte[] compress(byte[] uncompressed)
  {
    byte[] result = null;

    Deflater deflater = new Deflater();
    deflater.setInput(uncompressed);
    deflater.finish();

    // Create an expandable byte array to hold the compressed data. 
    // You cannot use an array that's the same size as the original because 
    // there is no guarantee that the compressed data will be smaller than 
    // the uncompressed data. 

    ByteArrayOutputStream bos = new ByteArrayOutputStream(uncompressed.length);

    // Compress the data 
    byte[] buf = new byte[1024];
    while (!deflater.finished())
    {
      int count = deflater.deflate(buf);
      bos.write(buf, 0, count);
    }
    deflater.end();

    try
    {
      bos.close();
    }
    catch (IOException e)
    {
      MBLog.w(TAG, "Unable to close stream");
    }

    // Get the compressed data 

    result = bos.toByteArray();

    return result;
  }

  /**
   * Decompress byte array 
   * 
   * @param compressed byte array
   * @return decompressed byte array
   */
  public byte[] decompress(byte[] compressed)
  {
    return decompress(compressed, 0);
  }

  public byte[] decompress(byte[] compressed, int bytesToSkip)
  {
    Inflater decompressor = new Inflater();
    decompressor.setInput(compressed, bytesToSkip, compressed.length - bytesToSkip);

    // Create an expandable byte array to hold the decompressed data 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(compressed.length);

    // Decompress the data 
    byte[] buf = new byte[1024];
    while (!decompressor.finished())
    {
      try
      {
        int count = decompressor.inflate(buf);
        bos.write(buf, 0, count);
      }
      catch (DataFormatException e)
      {
        decompressor.end();
        return null;
      }
    }
    decompressor.end();
    try
    {
      if (bos != null) bos.close();
    }
    catch (IOException e)
    {
      MBLog.w(TAG, "Unable to close stream");
    }

    // Get the decompressed data 
    byte[] decompressedData = bos.toByteArray();
    return decompressedData;
  }

}
/**
 * Reader
 */
interface Reader
{
  /**
   * Read file
   * 
   * @param filename file name
   * @return byte array
   */
  byte[] read(String filename);
}

// support for encrypted xml files
// those are stored in corresponding .glb files
// note: this method should just be called with .xml filenames
class ReadFromGLB implements Reader
{
  // this cache contains xml files which are already unobfuscated
  private final Map<String, byte[]> _cacheOfXml = new HashMap<String, byte[]>();

  @Override
  public byte[] read(String filename)
  {
    if (!filename.endsWith(".xml")) return null;

    synchronized (_cacheOfXml)
    {
      // note: the cache has the XML filename as the key
      byte[] dataFromCache = _cacheOfXml.get(filename);
      if (dataFromCache != null)
      {
        return dataFromCache;
      }
      // is the xml filename in the cache with a null value?
      // in that case, it means we tried to load the .glb before but it failed (not present)
      if (_cacheOfXml.containsKey(filename)) return null;
    } // end sync block

    // first time we try to load the corresponding .glb
    String glbName = filename.substring(0, filename.lastIndexOf('.')) + ".glb";
    byte[] glbFileData = DataUtil.getInstance().readFromAssetOrFile(glbName);
    if (glbFileData != null)
    {
      // glb found, but is it valid?
      if (glbFileData.length > 4 && glbFileData[0] == '-' && glbFileData[1] == 'i' && glbFileData[2] == 't' && glbFileData[3] == 'u')
      {
        glbFileData = unobfuscate(glbFileData);
        synchronized (_cacheOfXml)
        {
          _cacheOfXml.put(filename, glbFileData);
        }
        return glbFileData;
      }
    }
    // glb not found
    // in future do not try to load the GLB as it isnt present
    synchronized (_cacheOfXml)
    {
      _cacheOfXml.put(filename, null);
    }
    return null;
  }

  // xml files can be (slightly) obfuscated at deploy time
  // obfuscation is done by:
  // step 1: convert file using base64
  // step 2: use java.util.zip.Deflator to compress
  // step 3: write a special signature (binary -itu)
  // step 4: write the compressed stream
  // this routine reverses those steps
  private byte[] unobfuscate(byte[] data)
  {
    // reverse step 3:  write a special signature (binary -itu)
    // and 
    // Reversing step 2: use java.util.zip.Deflator to compress
    data = DataUtil.getInstance().decompress(data, 4);
    // reverse step 1: convert using base64
    Base64 b64 = new Base64();

    return b64.decode(data);
  }
}
class ReadFromAsset implements Reader
{

  @Override
  public byte[] read(String filename)
  {
    try
    {
      return AssetUtil.getInstance().getByteArray(filename);
    }
    catch (Exception e)
    {
      // do not show or propagate exception,
    }
    return null;
  }

}
class ReadFromFile implements Reader
{
  @Override
  public byte[] read(String filename)
  {
    try
    {
      return FileUtil.getInstance().getByteArray(filename);
    }
    catch (Exception e)
    {
      // do not show or propagate exception,
    }
    return null;
  }
}
/**
 * A special Reader that always returns null.
 * @author Gert
 *
 */
class ReadFromNone implements Reader
{
  @Override
  public byte[] read(String filename)
  {
    return null;
  }
}

class ReadFromAll
{
  private final ReadFromAsset _fromAsset = new ReadFromAsset();
  private final ReadFromFile  _fromFile  = new ReadFromFile();
  private final ReadFromGLB   _fromGlb   = new ReadFromGLB();

  public TwinResult<byte[], Reader> read(String filename)
  {
    Reader theReaderThatRead = _fromFile;
    byte[] result = theReaderThatRead.read(filename);
    if (result == null)
    {
      theReaderThatRead = _fromAsset;
      result = theReaderThatRead.read(filename);
      if (result == null)
      {
        theReaderThatRead = _fromGlb;
        result = theReaderThatRead.read(filename);
        if (result == null) theReaderThatRead = null;
      }
    }
    return new TwinResult<byte[], Reader>(result, theReaderThatRead);
  }
}




Java Source Code List

com.itude.mobile.android.util.AssertUtil.java
com.itude.mobile.android.util.AssetUtil.java
com.itude.mobile.android.util.ByteUtil.java
com.itude.mobile.android.util.CollectionUtilities.java
com.itude.mobile.android.util.ComparisonUtil.java
com.itude.mobile.android.util.ConvertedList.java
com.itude.mobile.android.util.DataUtil.java
com.itude.mobile.android.util.DateUtil.java
com.itude.mobile.android.util.DeviceUtil.java
com.itude.mobile.android.util.DoubleUtil.java
com.itude.mobile.android.util.FileUtil.java
com.itude.mobile.android.util.ItudeException.java
com.itude.mobile.android.util.MathUtil.java
com.itude.mobile.android.util.RunnableWithParam.java
com.itude.mobile.android.util.ScreenUtil.java
com.itude.mobile.android.util.StringUtil.java
com.itude.mobile.android.util.TwinResult.java
com.itude.mobile.android.util.UIUtil.java
com.itude.mobile.android.util.UniqueIntegerGenerator.java
com.itude.mobile.android.util.ValidationUtil.java
com.itude.mobile.android.util.ViewUtilities.java
com.itude.mobile.android.util.exceptions.DataParsingException.java
com.itude.mobile.android.util.exceptions.DateParsingException.java
com.itude.mobile.android.util.https.EasySSLSocketFactory.java
com.itude.mobile.android.util.https.EasyX509TrustManager.java
com.itude.mobile.android.util.log.MBLog.java