/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.util.*;
import javax.tv.service.*;
import javax.tv.locator.*;
import org.davic.net.dvb.*;

public class HermesUpgradeDownloader extends MPEGFilter {
 private Object syncobj;
 private boolean inited;

 private boolean infopacket;
 private int sec_cnt;
 private int sec_max;
 private boolean sec_received[];
 private boolean block_received[];
 private int block_cnt[];
 private int block_total[];

 private HermesUpgradeDownloader(String name,int onid,int tsid,int pid,int table_id,byte posfdef[],byte posfmask[]) {
  super(name,onid,tsid,pid,table_id,posfdef,posfmask);
  syncobj=new Object();
  inited=false;
 }

 public boolean match(byte data[]) {
  boolean res=false;

  int block_id=data[6]&0xff;
  int sec_id=(((data[8]&0xff)<<8)|(data[9]&0xff));

  if (!inited) {
   sec_cnt=0;
   sec_max=-1;

   sec_received=new boolean[HermesUpgrade.MAX_SECTION_COUNT];
   block_received=new boolean[HermesUpgrade.MAX_SECTION_COUNT*HermesUpgrade.MAX_BLOCK_COUNT];

   block_cnt=new int[HermesUpgrade.MAX_SECTION_COUNT];
   block_total=new int[HermesUpgrade.MAX_SECTION_COUNT];

   infopacket=false;
   inited=true;
  }

  if (!infopacket) {
   int block_max=(data[7]&0xff);

   if ((block_id==0)&&(block_max==0)&&(sec_id==0)) {
    HermesUpgrade.Info info=HermesUpgrade.extract_info(data);
    sec_max=info.sector_cnt+1;    

    infopacket=true;
    return true;    
   }

   return false;
  }

  if (sec_received[sec_id]) return false;

  int idx=(sec_id<<8)+block_id;

  if (!block_received[idx]) {
   res=true;
  }

  return res;
 }

 public void action(byte data[]) {
  try {
   Output.data(data);
   Output.flush();

   int block_id=data[6]&0xff;

   int sec_id=(((data[8]&0xff)<<8)|(data[9]&0xff));
   int idx=(sec_id<<8)+block_id;

   block_received[idx]=true;

   if (block_total[sec_id]==0) {
    int block_max=(data[7]&0xff)+1;
    block_total[sec_id]=block_max;
   }

   block_cnt[sec_id]++;

   if (block_cnt[sec_id]==block_total[sec_id]) {
    sec_received[sec_id]=true;
    sec_cnt++;
   }

   if (sec_cnt==sec_max) {
    synchronized(syncobj) {
     syncobj.notify();
    }
   }
  } catch(Throwable t) {}
 }

 public void collect_sections() throws Throwable {
  synchronized(syncobj) {
   syncobj.wait();
  }
 }

 public static HermesUpgradeDownloader create(int pid,int table_id,int download_id) {
  HermesUpgradeDownloader f=null;

  byte posfdef[]=new byte[2];
  posfdef[0]=(byte)((download_id>>8)&0xff);
  posfdef[1]=(byte)(download_id&0xff);

  byte posfmask[]=new byte[2];
  posfmask[0]=(byte)-1;
  posfmask[1]=(byte)-1;

  try {
   DvbLocator dvbloc=(DvbLocator)SrvUtils.current_service().getLocator();

   int onid=dvbloc.getOriginalNetworkId();
   int tsid=dvbloc.getTransportStreamId();

   String name="Hermes Upgrade Downloader [\""+dvbloc.toExternalForm()+"\",pid=0x"+Utils.hex_value(pid,4)+"]";

   f=new HermesUpgradeDownloader(name,onid,tsid,pid,table_id,posfdef,posfmask);
  } catch(Throwable t) {}

  return f;
 }

}
