File: TiCert.java - Tab length: 1 2 4 8 - Lines: on off - No wrap: on off

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ticert;

import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author SLO
 */
public class TiCert {
    private static List<Field> fields=new ArrayList<Field>();

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        if(args.length!=1) {
            System.out.println("need a filename");
            return;
        }

        String fname=args[0];
        System.out.println("Opening "+fname+"...");
        DataInputStream di=null;
        try {
            di = new DataInputStream(new FileInputStream(fname));
            manage(di);
        } catch (FileNotFoundException ex) {
            System.out.println("not found");
        } catch(EOFException ex) {
            System.out.println("End of file.");
        } catch(IOException ex) {
            System.out.println("Read error, abort!");
        } finally {
            try {
                di.close();
            } catch(Exception ex) {}
        }

    }

    private static String readFixedLengthString(DataInputStream di, int len) throws IOException {
        byte[] b= new byte[len];
        di.readFully(b);
        return new String(b).trim();
    }
   
    private static void manage(DataInputStream di) throws IOException {
        //skip tifile header
        String h=readFixedLengthString(di,8);
        System.out.println("header: "+h);
        int by;
        by=di.readUnsignedByte();if(by!=0x01) System.out.printf("warning(1), expected 0x01, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x00) System.out.printf("warning(2), expected 0x00, unexpected value %02X\n",by);
        //decode cert mem
        String folder=readFixedLengthString(di, 8);
        System.out.println("Folder name:"+folder);
        String comment=readFixedLengthString(di, 40);
        System.out.println("Comment:"+comment);
        by=di.readUnsignedByte();if(by!=0x01) System.out.printf("warning(3), expected 0x01, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x00) System.out.printf("warning(4), expected 0x00, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x52) System.out.printf("warning(5), expected 0x52, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x00) System.out.printf("warning(6), expected 0x00, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x00) System.out.printf("warning(7), expected 0x00, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x00) System.out.printf("warning(8), expected 0x00, unexpected value %02X\n",by);
        String var=readFixedLengthString(di, 8);
        System.out.println("Var name:"+var+" (should be certdump)");
        by=di.readUnsignedByte();
        System.out.printf("var type: 0x%02X\n",by);
        by=di.readUnsignedByte();if((by&0xfc)!=0x00) System.out.printf("warning(10), expected 0x00, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x00) System.out.printf("warning(11), expected 0x00, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x00) System.out.printf("warning(12), expected 0x00, unexpected value %02X\n",by);
        di.skipBytes(4); //pointer to eof
        by=di.readUnsignedByte();if(by!=0xa5) System.out.printf("warning(13), expected 0xa5, unexpected value %02X\n",by);
        by=di.readUnsignedByte();if(by!=0x5a) System.out.printf("warning(14), expected 0x5a, unexpected value %02X\n",by);
        //now read data!
        readcert(di);

        Field mod=findField(0x020);
        if(mod==null) {
            System.out.println("modulus not found");
            return;
        }
        System.out.printf("Modulus length: %d\n",mod.getLength()*8);
        BigInteger b=new BigInteger(1, mod.getData());
        System.out.println("Modulus:");
        System.out.println(b.toString());
    }

    private static void readcert(DataInputStream di) throws IOException {

        System.out.println("now reading certificate");
        //skip 10 bytes header
        di.skipBytes(10);
        boolean ok=true;
        while(ok) {
            int tag=di.readUnsignedShort();
            int lencode=tag&0x0F;
            int len;
            tag = tag>>>4;
            System.out.printf("tag=0x%03X\n",tag);
            if(lencode<=0x0C) {
                len=lencode;
            } else if(lencode==0x0D) {
                len=di.readUnsignedByte();
            } else if(lencode==0x0E) {
                len=di.readUnsignedShort();
            } else {
                System.out.println("reading extra long fields is not supported, this is eof");
                return;
            }
            System.out.printf("len=%d\n",len);
            try {
                Field f=new Field(tag,len,di);
                fields.add(f);
            } catch(EOFException ex) {
                ok=false;
            }
        }
    }

    private static Field findField(int tag) {
        for(Field f:fields) {
            if(f.getTag()==tag) return f;
        }
        return null;
    }

    private static class Field {
        private int tag;
        private int len;
        private byte[] data;

        public Field(int tag, int len, DataInputStream d) throws IOException {
            this.tag=tag;
            this.len=len;
            data=new byte[len];
            d.readFully(data);
        }

        public int getTag() {
            return tag;
        }

        public int getLength() {
            return len;
        }

        public byte[] getData() {
            return data;
        }
    }

}

/*
  http://www.ticalc.org/cgi-bin/zipview?text/calcinfo/file_format.zip;file_format/ti89_92_92+/ti89_92_92+.txt
  Adress                What It Contains
  ---------------------------------------------------------------
  0x00-0x07 0-7         **TI92** or **TI92P*
  0x08-0x09 8-9         0x01 0x00
  0x0A-0x11 10-17           folder name (8 chars)
  0x12-0x39 18-57           comment (40 chars)
  0x3A-0x3B 58-59           0x01 0x00 (number of vars: 1)
  0x3C-0x3F 60-63           0x52 0x00 0x00 0x00 (1)
  0x40-0x47 64-71           varname (8 chars)
  0x48-0x49 72-73           vartype 0x00
  0x4A-0x4B 74-75           0x00 0x00
  0x4C-0x4F 76-79           (2)
  0x50-0x51 80-81           0xA5 0x5A
  0x52-0x.. 82-(n-1)        data (raw data part)
  0x..-0x.. n-(n+1)         checksum (raw data part)

 */