// Path: java/src/main/java/kanzi/ByteTransform.java
// public interface ByteTransform
// {
//    // Read src.length bytes from src.array[src.index], process them and
//    // write them to dst.array[dst.index]. The index of each slice is updated
//    // with the number of bytes respectively read from and written to.
//    public boolean forward(SliceByteArray src, SliceByteArray dst);
// 
// 
//    // Read src.length bytes from src.array[src.index], process them and
//    // write them to dst.array[dst.index]. The index of each slice is updated
//    // with the number of bytes respectively read from and written to.
//    public boolean inverse(SliceByteArray src, SliceByteArray dst);
// 
// 
//    // Return the max size required for the output buffer
//    public int getMaxEncodedLength(int srcLength);
// }
// 
// Path: java/src/main/java/kanzi/SliceByteArray.java
// public final class SliceByteArray
// {
//     public byte[] array; // array.length is the slice capacity
//     public int length;
//     public int index;
// 
// 
//     public SliceByteArray()
//     {
//        this(new byte[0], 0, 0);
//     }
// 
// 
//     public SliceByteArray(byte[] array, int idx)
//     {
//         if (array == null)
//            throw new NullPointerException("The array cannot be null");
// 
//         if (idx < 0)
//            throw new NullPointerException("The index cannot be negative");
// 
//         this.array = array;
//         this.length = array.length;
//         this.index = idx;
//     }
// 
// 
//     public SliceByteArray(byte[] array, int length, int idx)
//     {
//         if (array == null)
//            throw new NullPointerException("The array cannot be null");
// 
//         if (length < 0)
//            throw new IllegalArgumentException("The length cannot be negative");
// 
//         if (idx < 0)
//            throw new NullPointerException("The index cannot be negative");
// 
//         this.array = array;
//         this.length = length;
//         this.index = idx;
//     }
// 
// 
//     @Override
//     public boolean equals(Object o)
//     {
//         try
//         {
//             if (o == null)
//                return false;
// 
//             if (this == o)
//                return true;
// 
//             SliceByteArray sa = (SliceByteArray) o;
//             return ((this.array == sa.array)   &&
//                     (this.length == sa.length) &&
//                     (this.index == sa.index));
//         }
//         catch (ClassCastException e)
//         {
//             return false;
//         }
//     }
// 
// 
//     @Override
//     public int hashCode()
//     {
//        return Objects.hashCode(this.array);
//     }
// 
// 
//     @Override
//     @SuppressWarnings("lgtm [java/print-array]")
//     public String toString()
//     {
//         StringBuilder builder = new StringBuilder(100);
//         builder.append("[ data=");
//         builder.append(String.valueOf(this.array));
//         builder.append(", len=");
//         builder.append(this.length);
//         builder.append(", idx=");
//         builder.append(this.index);
//         builder.append("]");
//         return builder.toString();
//     }
// 
// 
//     public static boolean isValid(SliceByteArray sa)
//     {
//        if (sa == null)
//           return false;
// 
//        if (sa.array == null)
//           return false;
// 
//        if (sa.index < 0)
//           return false;
// 
//        if (sa.length < 0)
//           return false;
// 
//        return (sa.index <= sa.array.length);
//     }
// }


import java.util.Map;
import kanzi.ByteTransform;
import kanzi.SliceByteArray;
   {
      if (input.length == 0)
         return true;

      if (input.array == output.array)
         return false;

      int blockSize = input.length;
      final int chunks = BWT.getBWTChunks(blockSize);

      for (int i=0; i<chunks; i++)
      {
         // Read block header (mode + primary index). See top of file for format
         final int blockMode = input.array[input.index++] & 0xFF;
         final int pIndexSizeBytes = 1 + ((blockMode >>> 6) & 0x03);

         if (input.length < pIndexSizeBytes)
             return false;

         input.length -= pIndexSizeBytes;
         int shift = (pIndexSizeBytes - 1) << 3;
         int primaryIndex = (blockMode & 0x3F) << shift;

         // Extract BWT primary index
         for (int n=1; n<pIndexSizeBytes; n++)
         {
            shift -= 8;
            primaryIndex |= ((input.array[input.index++] & 0xFF) << shift);
         }

// Path: java/src/main/java/kanzi/ByteTransform.java
// public interface ByteTransform
// {
//    // Read src.length bytes from src.array[src.index], process them and
//    // write them to dst.array[dst.index]. The index of each slice is updated
//    // with the number of bytes respectively read from and written to.
//    public boolean forward(SliceByteArray src, SliceByteArray dst);
// 
// 
//    // Read src.length bytes from src.array[src.index], process them and
//    // write them to dst.array[dst.index]. The index of each slice is updated
//    // with the number of bytes respectively read from and written to.
//    public boolean inverse(SliceByteArray src, SliceByteArray dst);
// 
// 
//    // Return the max size required for the output buffer
//    public int getMaxEncodedLength(int srcLength);
// }
// 
// Path: java/src/main/java/kanzi/SliceByteArray.java
// public final class SliceByteArray
// {
//     public byte[] array; // array.length is the slice capacity
//     public int length;
//     public int index;
// 
// 
//     public SliceByteArray()
//     {
//        this(new byte[0], 0, 0);
//     }
// 
// 
//     public SliceByteArray(byte[] array, int idx)
//     {
//         if (array == null)
//            throw new NullPointerException("The array cannot be null");
// 
//         if (idx < 0)
//            throw new NullPointerException("The index cannot be negative");
// 
//         this.array = array;
//         this.length = array.length;
//         this.index = idx;
//     }
// 
// 
//     public SliceByteArray(byte[] array, int length, int idx)
//     {
//         if (array == null)
//            throw new NullPointerException("The array cannot be null");
// 
//         if (length < 0)
//            throw new IllegalArgumentException("The length cannot be negative");
// 
//         if (idx < 0)
//            throw new NullPointerException("The index cannot be negative");
// 
//         this.array = array;
//         this.length = length;
//         this.index = idx;
//     }
// 
// 
//     @Override
//     public boolean equals(Object o)
//     {
//         try
//         {
//             if (o == null)
//                return false;
// 
//             if (this == o)
//                return true;
// 
//             SliceByteArray sa = (SliceByteArray) o;
//             return ((this.array == sa.array)   &&
//                     (this.length == sa.length) &&
//                     (this.index == sa.index));
//         }
//         catch (ClassCastException e)
//         {
//             return false;
//         }
//     }
// 
// 
//     @Override
//     public int hashCode()
//     {
//        return Objects.hashCode(this.array);
//     }
// 
// 
//     @Override
//     @SuppressWarnings("lgtm [java/print-array]")
//     public String toString()
//     {
//         StringBuilder builder = new StringBuilder(100);
//         builder.append("[ data=");
//         builder.append(String.valueOf(this.array));
//         builder.append(", len=");
//         builder.append(this.length);
//         builder.append(", idx=");
//         builder.append(this.index);
//         builder.append("]");
//         return builder.toString();
//     }
// 
// 
//     public static boolean isValid(SliceByteArray sa)
//     {
//        if (sa == null)
//           return false;
// 
//        if (sa.array == null)
//           return false;
// 
//        if (sa.index < 0)
//           return false;
// 
//        if (sa.length < 0)
//           return false;
// 
//        return (sa.index <= sa.array.length);
//     }
// }


// Path: java/src/main/java/kanzi/transform/BWTBlockCodec.java
import java.util.Map;
import kanzi.ByteTransform;
import kanzi.SliceByteArray;

   {
      if (input.length == 0)
         return true;

      if (input.array == output.array)
         return false;

      int blockSize = input.length;
      final int chunks = BWT.getBWTChunks(blockSize);

      for (int i=0; i<chunks; i++)
      {
         // Read block header (mode + primary index). See top of file for format
         final int blockMode = input.array[input.index++] & 0xFF;
         final int pIndexSizeBytes = 1 + ((blockMode >>> 6) & 0x03);

         if (input.length < pIndexSizeBytes)
             return false;

         input.length -= pIndexSizeBytes;
         int shift = (pIndexSizeBytes - 1) << 3;
         int primaryIndex = (blockMode & 0x3F) << shift;

         // Extract BWT primary index
         for (int n=1; n<pIndexSizeBytes; n++)
         {
            shift -= 8;
            primaryIndex |= ((input.array[input.index++] & 0xFF) << shift);
         }

         if (this.bwt.setPrimaryIndex(i, primaryIndex) == false)