/**
  * Verify that all is OK with the codeword array.
  *
  * @param codewords
  * @return an index to the first data codeword.
  * @throws FormatException
  */
 private static void verifyCodewordCount(int[] codewords, int numECCodewords)
     throws FormatException {
   if (codewords.length < 4) {
     // Codeword array size should be at least 4 allowing for
     // Count CW, At least one Data CW, Error Correction CW, Error Correction CW
     throw FormatException.getFormatInstance();
   }
   // The first codeword, the Symbol Length Descriptor, shall always encode the total number of
   // data
   // codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and
   // pad
   // codewords, but excluding the number of error correction codewords.
   int numberOfCodewords = codewords[0];
   if (numberOfCodewords > codewords.length) {
     throw FormatException.getFormatInstance();
   }
   if (numberOfCodewords == 0) {
     // Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error
     // Codewords)
     if (numECCodewords < codewords.length) {
       codewords[0] = codewords.length - numECCodewords;
     } else {
       throw FormatException.getFormatInstance();
     }
   }
 }
 /**
  * Given data and error-correction codewords received, possibly corrupted by errors, attempts to
  * correct the errors in-place using Reed-Solomon error correction.
  *
  * @param codewords data and error correction codewords
  * @throws ChecksumException if error correction fails
  */
 private static int correctErrors(int[] codewords, int[] erasures, int numECCodewords)
     throws FormatException {
   if ((erasures != null && erasures.length > numECCodewords / 2 + MAX_ERRORS)
       || (numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS)) {
     // Too many errors or EC Codewords is corrupted
     throw FormatException.getFormatInstance();
   }
   // Try to correct the errors
   // TODO enable error correction
   int result = 0; // rsDecoder.correctErrors(codewords, numECCodewords);
   if (erasures != null) {
     int numErasures = erasures.length;
     if (result > 0) {
       numErasures -= result;
     }
     if (numErasures > MAX_ERRORS) {
       // Still too many errors
       throw FormatException.getFormatInstance();
     }
   }
   return result;
 }
  /**
   * Decodes a PDF417 Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a
   * black module.
   *
   * @param bits booleans representing white/black PDF417 Code modules
   * @return text and bytes encoded within the PDF417 Code
   * @throws FormatException if the PDF417 Code cannot be decoded
   */
  public DecoderResult decode(BitMatrix bits) throws FormatException {
    // Construct a parser to read the data codewords and error-correction level
    BitMatrixParser parser = new BitMatrixParser(bits);
    int[] codewords = parser.readCodewords();
    if (codewords == null || codewords.length == 0) {
      throw FormatException.getFormatInstance();
    }

    int ecLevel = parser.getECLevel();
    int numECCodewords = 1 << (ecLevel + 1);
    int[] erasures = parser.getErasures();

    correctErrors(codewords, erasures, numECCodewords);
    verifyCodewordCount(codewords, numECCodewords);

    // Decode the codewords
    return DecodedBitStreamParser.decode(codewords);
  }