Package com.ettrema.zsync

Source Code of com.ettrema.zsync.MetaFileReader

/* MetafileReader.java

MetafileReader: Metafile reader class
Copyright (C) 2011 Tomáš Hlavnička <hlavntom@fel.cvut.cz>

This file is a part of Jazsync.

Jazsync 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.

Jazsync 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 Jazsync; if not, write to the

Free Software Foundation, Inc.,
59 Temple Place, Suite 330,
Boston, MA  02111-1307
USA
*/
package com.ettrema.zsync;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import com.ettrema.zsync.HeaderMaker.Headers;
import com.ettrema.zsync.MetaFileMaker.MetaData;


/**
* Class used to read metafile
* @author Tomáš Hlavnička
*/
public class MetaFileReader {

  private ChainingHash hashtable;
  private int fileOffset;
  private int blockNum;
 
  /** Variables for header information from .zsync metafile */
  //------------------------------
  private Headers headers;


  public MetaFileReader(File metafile) {
    readMetaFile(metafile);
    blockNum = (int) Math.ceil((double) headers.length / (double) headers.blocksize);
    readChecksums(metafile)
  }

  public MetaFileReader(MetaData metaData) {
    this.headers = metaData.getHeaders();   
    blockNum = (int) Math.ceil((double) headers.length / (double) headers.blocksize);
    fillHashTable(metaData.getChecksums());
   
  }

  /**
   * Parsing method for metafile headers, saving each value into separate variable.
   * @param s String containing metafile
   * @return Boolean value notifying whether header ended or not (true = end of header)
   */
  private boolean parseHeader(String s) {
    String subs;
    int colonIndex;
    if (s.equals("")) {
      //timto prazdnym radkem skoncil header, muzeme prestat cist
      return true;
    }
    colonIndex = s.indexOf(":");
    subs = s.substring(0, colonIndex);
    if (subs.equalsIgnoreCase("zsync")) {
      headers.version = s.substring(colonIndex + 2);
      //zkontrolujeme kompatibilitu
      if (headers.version.equals("0.0.4") || headers.version.equals("0.0.2")) {
        throw new RuntimeException("This version is not compatible with zsync streams in versions up to 0.0.4");
      }
    } else if (subs.equalsIgnoreCase("Blocksize")) {
      headers.blocksize = Integer.parseInt(s.substring(colonIndex + 2));
    } else if (subs.equalsIgnoreCase("Length")) {
      headers.length = Long.parseLong(s.substring(colonIndex + 2));
    } else if (subs.equalsIgnoreCase("Hash-Lengths")) {
      int comma = s.indexOf(",");
      int seqNum = Integer.parseInt(s.substring((colonIndex + 2), comma));
      headers.setSeqNum(seqNum);
      int nextComma = s.indexOf(",", comma + 1);
      headers.setRsumBytes( Integer.parseInt(s.substring(comma + 1, nextComma)) );
      headers.setChecksumBytes( Integer.parseInt(s.substring(nextComma + 1)) );
      if ((headers.getSeqNum() < 1 || headers.getSeqNum() > 2)
          || (headers.getRsumButes() < 1 || headers.getRsumButes() > 4)
          || (headers.getChecksumBytes() < 3 || headers.getChecksumBytes() > 16)) {
        throw new RuntimeException("Nonsensical hash lengths line " + s.substring(colonIndex + 2));
      }

    } else if (subs.equalsIgnoreCase("URL")) {
      headers.url = s.substring(colonIndex + 2);
    } else if (subs.equalsIgnoreCase("Z-URL")) {
      //not implemented yet
    } else if (subs.equalsIgnoreCase("SHA-1")) {
      headers.sha1 = s.substring(colonIndex + 2);
    } else if (subs.equalsIgnoreCase("Z-Map2")) {
      //not implemented yet
    }
    return false;
  }

  /**
   * Method reads metafile from file and reads
   * it line by line, sending line String to parser.
   */
  private void readMetaFile(File metafile) {
    headers = new Headers();
    try {
      BufferedReader in = new BufferedReader(new FileReader(metafile));
      String s;
      while ((s = in.readLine()) != null) {
        if (parseHeader(s)) {
          break;
        }
      }
      in.close();
    } catch (IOException e) {
      throw new RuntimeException("IO problem in metafile header reading", e);
    }
  }

  /**
   * Method that reads metafile from file and stores its content into byte array
   * and saves offset where headers end and blocksums starts.
   */
  private void readChecksums(File metafile) {
    long length = metafile.length();
    if (metafile.length() > Integer.MAX_VALUE) {
      throw new RuntimeException("Metafile is too large");
    }
    byte[] bytes = new byte[(int) length];

    try {
      InputStream is = new FileInputStream(metafile);
      int offset = 0;
      int n = 0;
      while (offset < bytes.length && (n = is.read(bytes, offset, bytes.length - offset)) >= 0) {
        offset += n;
      }

      // Presvedcime se, ze jsme precetli cely soubor
      if (offset < bytes.length) {
        throw new IOException("Could not completely read file " + metafile.getName());
      }

      is.close();
    } catch (IOException e) {
      throw new RuntimeException("IO problem in metafile reading", e);
    }
    // urci offset, kde konci hlavicka a zacinaji kontrolni soucty
    fileOffset = 0;
    for (int i = 2; i < bytes.length; i++) {
      if (bytes[i - 2] == 10 && bytes[i - 1] == 10) {
        fileOffset = i;
        break;
      }
    }
    fillHashTable(bytes);
  }

  private void fillHashTable(List<ChecksumPair> list) {
    int i = 16;
    //spocteme velikost hashtable podle poctu bloku dat
    while ((2 << (i - 1)) > blockNum && i > 4) {
      i--;
    }
    //vytvorime hashtable o velikosti 2^i (max. 2^16, min. 2^4)
    hashtable = new ChainingHash(2 << (i - 1));
    for( ChecksumPair pair : list ) {
      hashtable.insert(pair);
    }
  }
 
  /**
   * Fills a chaining hash table with ChecksumPairs
   * @param checksums Byte array with bytes of whole metafile
   */
  private void fillHashTable(byte[] checksums) {
    int i = 16;
    //spocteme velikost hashtable podle poctu bloku dat
    while ((2 << (i - 1)) > blockNum && i > 4) {
      i--;
    }
    //vytvorime hashtable o velikosti 2^i (max. 2^16, min. 2^4)
    hashtable = new ChainingHash(2 << (i - 1));
    ChecksumPair p = null;
    //Link item;
    int offset = 0;
    int weakSum = 0;
    int seq = 0;
    int off = fileOffset;

    byte[] weak = new byte[4];
    byte[] strongSum = new byte[headers.getChecksumBytes()];

    while (seq < blockNum) {

      for (int w = 0; w < headers.getRsumButes(); w++) {
        weak[w] = checksums[off];
        off++;
      }

      for (int s = 0; s < strongSum.length; s++) {
        strongSum[s] = checksums[off];
        off++;
      }

      weakSum = 0;
      weakSum += (weak[2] & 0x000000FF) << 24;
      weakSum += (weak[3] & 0x000000FF) << 16;
      weakSum += (weak[0] & 0x000000FF) << 8;
      weakSum += (weak[1] & 0x000000FF);

      p = new ChecksumPair(weakSum, strongSum.clone(), offset, headers.blocksize, seq);
      offset += headers.blocksize;
      seq++;
      //item = new Link(p);
      hashtable.insert(p);
    }
  }

  /**
   * Returns hash table cotaining block checksums
   * @return Hash table
   */
  public ChainingHash getHashtable() {
    return hashtable;
  }

  /**
   * Returns number of blocks in complete file
   * @return Number of blocks
   */
  public int getBlockCount() {
    return blockNum;
  }

  /**
   * Returns size of block
   * @return Size of the data block
   */
  public int getBlocksize() {
    return headers.blocksize;
  }

  /**
   * Length of used strong sum
   * @return Length of strong sum
   */
  public int getChecksumBytes() {
    return headers.getChecksumBytes();
  }

  /**
   * Returns length of complete file
   * @return Length of the file
   */
  public long getLength() {
    return headers.length;
  }


  /**
   * Length of used weak sum
   * @return Length of weak sum
   */
  public int getRsumBytes() {
    return headers.getRsumButes();
  }

  /**
   * Number of consequence blocks
   * @return Number of consequence blocks
   */
  public int getSeqNum() {
    return headers.getSeqNum();
  }

  /**
   * Returns SHA1sum of complete file
   * @return String containing SHA1 sum of complete file
   */
  public String getSha1() {
    return headers.sha1;
  }
}
TOP

Related Classes of com.ettrema.zsync.MetaFileReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.