/*
 *
 * TerminatedFile - Tim Tyler 2000.
 * 
 * This code has been placed in the public domain.
 * You can do what you like with it.
 * Note that this code comes with no warranty.
 *
 */

/*
 * To Do:
 *
 */

   class TerminatedFile {
      public int start = 0;
      public int length = 0;
   
      public byte data[];
   
      public int block_size; // in bytes - e.g. 16
   
      final static byte PAD  = (byte)0x00;
      final static byte MARK = (byte)0x01;
      final static byte DUD  = (byte)0xA5; // anything - but *not* one of the above values...
   
      void setGranularity(int n) {
         block_size = n;
      }
   
   
      void append(byte b) {
         data[length++] = b;
      }
   
   
      void appendMark(byte m, byte p) {
         data[length++] = m;
         for (int i = 1; i < block_size; i++) {
            data[length++] = p;
         }
      }
   
   
      void scrubLastCharacter() {
         length--;
      }
   
   
      void scrubLastBlock() {
         length -= block_size;
      }
   
   
      void makePaddableByteFile() {
         if (getByte(length - 1) == PAD) {
            append(MARK);
         }
         else
         {
            int i = 1;
            while (getByte(length - i) == MARK) {
               i++;
            }
         
            if (getByte(length - i) == PAD) {
               append(MARK);
            }
         }
      }
   
   
      void unmakePaddableByteFile() {
         int i = 1;
         while (getByte(length - i) == MARK) {
            i++;
         }
      
         if (getByte(length - i) == PAD) {
            scrubLastCharacter();
         }
      }
   
   
      void makePaddableBlockFile() {
         if (getBlock(length - block_size).isPadding(PAD)) {
            appendMark(MARK, PAD);
         }
         else
         {
            int i = block_size;
            while (getBlock(length - i).isMark(MARK, PAD)) {
               i += block_size;
            }
         
            if (getBlock(length - i).isPadding(PAD)) {
               appendMark(MARK, PAD);
            }
         }
      }
   
   
      void unmakePaddableBlockFile() {
         int i = block_size;
         while (getBlock(length - i).isMark(MARK, PAD)) {
            i += block_size;
         }
      
         if (getBlock(length - i).isPadding(PAD)) {
            scrubLastBlock();
         }
      }
   
   
      void addPadding(int over) {
         while (((length - start + over) % block_size) != 0) {
            append(PAD);
         }
      }
   
   
      void removePadding() {
         while (getByte(length - 1) == PAD) {
            scrubLastCharacter();
         }
      }
   
      void addConstant(int c) {
         int i = start;
         int temp;
         int carry = c;
      
         while ((carry != 0) && (i < length)) {
            temp = (data[i] & 0xff) + carry;
            data[i++] = (byte)(temp);
            carry = (temp > 0xff) ? 1 : 0;
         }
      
         if ((i >= length) && (carry != 0)) {
            append((byte)0);
         }
      }
   
   
      void subtractConstant(int c) {
         int i = start;
         int temp;
         int carry = c;
      
         while ((carry != 0) && (i < length)) {
            temp = (data[i] & 0xff) - carry;
            data[i++] = (byte)(temp);
            carry = (temp < 0) ? 1 : 0;
         }
      
         if ((i >= length) && (carry != 0)) {
            scrubLastCharacter();
         }
      }
   
   
   // ignores start currently...
      void xorChecksum() {
         if (length >= 16) {
            byte[] cs = Checksum.checksum(this, 16);
            for (int i = 0; i < 16; i++) {
               data[i] ^= cs[i];
            }
         }
      }
   
   
      Block getBlock(int offset) {
         return new Block(this, offset, block_size);
      }
   
   
   /** "safely" get byte at offset */
      byte getByte(int i) {
         if (i < start) {
            return DUD;
         }
      
         if (i >= length) {
            return DUD;
         }
      
         return data[i];
      }
   
   
   /** append n random bytes */
      void addRandomPadding(int n) {
         for (int i = 0; i < n; i++) {
            append(BIAES.getRandomByte());
         }
      }
   
   
      public static void main(String args[]) {
         BIAESFrEnd.main(args);
      }
   
   }