public synchronized void write(byte[] b,int off,int len) throws IOException, FileEncryptionException, FileIntegrityException {
  if (!exists() || realLength() == 0) {
    throw new FileEncryptionException("File has not been initialized properly!");
  }
  try {
    if (writeRecursionProtector > 1) {
      throw new FileEncryptionException("write recursion level exceeded!");
    }
 else {
      writeRecursionProtector++;
    }
    if ((b == null) || ((b.length - off) < len))     throw new IOException("buffer null or empty");
    long curpos=getFilePointer();
    int offset=(int)currentchunkoffset();
    boolean singlechunk=(len <= (CHUNK_DATA_SIZE - offset));
    if (singlechunk) {
      byte[] tmp=Arrays.copyOfRange(b,off,off + len);
      if ((length() == 0) && (curpos == 0)) {
        writeLastChunk(tmp,0);
        skipBytes(len);
        writeRecursionProtector--;
        return;
      }
      if (currentchunkpointer() < lastchunkpointer()) {
        if ((len == CHUNK_DATA_SIZE) && (offset == 0)) {
          writeChunk(tmp,currentchunkpointer());
          skipBytes(len);
        }
 else {
          byte[] decChunk=readChunk(currentchunkpointer());
          if (offset >= decChunk.length) {
            throw new FileEncryptionException("read() offset mismatch in decrypted data!");
          }
          System.arraycopy(b,off,decChunk,offset,len);
          writeChunk(decChunk,currentchunkpointer());
          skipBytes(len);
        }
      }
 else       if (currentchunkpointer() == lastchunkpointer()) {
        byte[] decChunk=readLastChunk(currentchunkpointer());
        byte[] merged=new byte[Math.max(decChunk.length,offset + len)];
        System.arraycopy(decChunk,0,merged,0,decChunk.length);
        System.arraycopy(b,off,merged,offset,len);
        writeLastChunk(merged,currentchunkpointer());
        skipBytes(len);
      }
 else {
        long idx_newlastchunk=currentchunkpointer();
        long idx_oldlastchunk=lastchunkpointer();
        long diff=idx_newlastchunk - idx_oldlastchunk - 1;
        byte[] decChunk=readLastChunk(idx_oldlastchunk);
        byte[] chunk=new byte[CHUNK_DATA_SIZE];
        System.arraycopy(decChunk,0,chunk,0,decChunk.length);
        Arrays.fill(chunk,decChunk.length,CHUNK_DATA_SIZE,(byte)0x00);
        writeChunk(chunk,idx_oldlastchunk);
        skipBytes(CHUNK_DATA_SIZE);
        for (long i=diff; i > 0; i--) {
          Arrays.fill(chunk,(byte)0x00);
          writeChunk(chunk,idx_newlastchunk - i);
          skipBytes(CHUNK_DATA_SIZE);
        }
        byte[] lastchunk=new byte[offset + len];
        Arrays.fill(lastchunk,0,offset,(byte)0x00);
        System.arraycopy(b,off,lastchunk,offset,len);
        writeLastChunk(lastchunk,idx_newlastchunk);
        skipBytes(lastchunk.length);
      }
      writeRecursionProtector--;
    }
 else {
      int preceding=0;
      if (offset != 0) {
        preceding=CHUNK_DATA_SIZE - offset;
        if (preceding > 0) {
          write(b,off,preceding);
        }
      }
      int nchunks=(len - preceding) / CHUNK_DATA_SIZE;
      for (int i=0; i < nchunks; i++) {
        write(b,off + preceding + (i * CHUNK_DATA_SIZE),CHUNK_DATA_SIZE);
      }
      int remainder=(len - preceding) % CHUNK_DATA_SIZE;
      if (remainder > 0) {
        write(b,off + preceding + (nchunks * CHUNK_DATA_SIZE),remainder);
      }
      writeRecursionProtector--;
    }
  }
 catch (  InvalidKeyException|InvalidAlgorithmParameterException|IllegalBlockSizeException|BadPaddingException|ShortBufferException|RandomDataGenerationException e) {
    throw new FileEncryptionException("Error during write()",e);
  }
}

public synchronized void write ( byte [ ] b , int off , int len ) throws IOException , FileEncryptionException , FileIntegrityException { if ( ! exists ( ) || realLength ( ) == 0 ) { throw new FileEncryptionException ( "File has not been initialized properly!" ) ; } try { if ( writeRecursionProtector > 1 ) { throw new FileEncryptionException ( "write recursion level exceeded!" ) ; } else { writeRecursionProtector ++ ; } if ( ( b == null ) || ( ( b . length - off ) < len ) ) throw new IOException ( "buffer null or empty" ) ; long curpos = getFilePointer ( ) ; int offset = ( int ) currentchunkoffset ( ) ; boolean singlechunk = ( len <= ( CHUNK_DATA_SIZE - offset ) ) ; if ( singlechunk ) { byte [ ] tmp = Arrays . copyOfRange ( b , off , off + len ) ; if ( ( length ( ) == 0 ) && ( curpos == 0 ) ) { writeLastChunk ( tmp , 0 ) ; skipBytes ( len ) ; writeRecursionProtector -- ; return ; } if ( currentchunkpointer ( ) < lastchunkpointer ( ) ) { if ( ( len == CHUNK_DATA_SIZE ) && ( offset == 0 ) ) { writeChunk ( tmp , currentchunkpointer ( ) ) ; skipBytes ( len ) ; } else { byte [ ] decChunk = readChunk ( currentchunkpointer ( ) ) ; if ( offset >= decChunk . length ) { throw new FileEncryptionException ( "read() offset mismatch in decrypted data!" ) ; } System . arraycopy ( b , off , decChunk , offset , len ) ; writeChunk ( decChunk , currentchunkpointer ( ) ) ; skipBytes ( len ) ; } } else if ( currentchunkpointer ( ) == lastchunkpointer ( ) ) { byte [ ] decChunk = readLastChunk ( currentchunkpointer ( ) ) ; byte [ ] merged = new byte [ Math . max ( decChunk . length , offset + len ) ] ; System . arraycopy ( decChunk , 0 , merged , 0 , decChunk . length ) ; System . arraycopy ( b , off , merged , offset , len ) ; writeLastChunk ( merged , currentchunkpointer ( ) ) ; skipBytes ( len ) ; } else { long idx_newlastchunk = currentchunkpointer ( ) ; long idx_oldlastchunk = lastchunkpointer ( ) ; long diff = idx_newlastchunk - idx_oldlastchunk - 1 ; byte [ ] decChunk = readLastChunk ( idx_oldlastchunk ) ; byte [ ] chunk = new byte [ CHUNK_DATA_SIZE ] ; System . arraycopy ( decChunk , 0 , chunk , 0 , decChunk . length ) ; Arrays . fill ( chunk , decChunk . length , CHUNK_DATA_SIZE , ( byte ) 0x00 ) ; writeChunk ( chunk , idx_oldlastchunk ) ; skipBytes ( CHUNK_DATA_SIZE ) ; for ( long i = diff ; i > 0 ; i -- ) { Arrays . fill ( chunk , ( byte ) 0x00 ) ; writeChunk ( chunk , idx_newlastchunk - i ) ; skipBytes ( CHUNK_DATA_SIZE ) ; } byte [ ] lastchunk = new byte [ offset + len ] ; Arrays . fill ( lastchunk , 0 , offset , ( byte ) 0x00 ) ; System . arraycopy ( b , off , lastchunk , offset , len ) ; writeLastChunk ( lastchunk , idx_newlastchunk ) ; skipBytes ( lastchunk . length ) ; } writeRecursionProtector -- ; } else { int preceding = 0 ; if ( offset != 0 ) { preceding = CHUNK_DATA_SIZE - offset ; if ( preceding > 0 ) { write ( b , off , preceding ) ; } } int nchunks = ( len - preceding ) / CHUNK_DATA_SIZE ; for ( int i = 0 ; i < nchunks ; i ++ ) { write ( b , off + preceding + ( i * CHUNK_DATA_SIZE ) , CHUNK_DATA_SIZE ) ; } int remainder = ( len - preceding ) % CHUNK_DATA_SIZE ; if ( remainder > 0 ) { write ( b , off + preceding + ( nchunks * CHUNK_DATA_SIZE ) , remainder ) ; } writeRecursionProtector -- ; } } catch ( InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException | ShortBufferException | RandomDataGenerationException e ) { throw new FileEncryptionException ( "Error during write()" , e ) ; } }
encrypts and writes the given byte array to the file . if the number of bytes to write exceed the chunk - size , the array in split and recursively written in multiple write calls .
