docs: static DataBlock[] getDataBlocks(byte[] rawCodewords,
                                     Version version,
                                     ErrorCorrectionLevel ecLevel) {
  
      if (rawCodewords.length != version.getTotalCodewords()) {
        throw new IllegalArgumentException();
      }
  
      // Figure out the number and size of data blocks used by this version and
      // error correction level
      Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
  
      // First count the total number of data blocks
      int totalBlocks = 0;
      Version.ECB[] ecBlockArray = ecBlocks.getECBlocks();
      for (Version.ECB ecBlock : ecBlockArray) {
        totalBlocks += ecBlock.getCount();
      }
  
      // Now establish DataBlocks of the appropriate size and number of data codewords
      DataBlock[] result = new DataBlock[totalBlocks];
      int numResultBlocks = 0;
      for (Version.ECB ecBlock : ecBlockArray) {
        for (int i = 0; i < ecBlock.getCount(); i++) {
          int numDataCodewords = ecBlock.getDataCodewords();
          int numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;
          result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);
        }
      }
  
      // All blocks have the same amount of data, except that the last n
      // (where n may be 0) have 1 more byte. Figure out where these start.
      int shorterBlocksTotalCodewords = result[0].codewords.length;
      int longerBlocksStartAt = result.length - 1;
      while (longerBlocksStartAt >= 0) {
        int numCodewords = result[longerBlocksStartAt].codewords.length;
        if (numCodewords == shorterBlocksTotalCodewords) {
          break;
        }
        longerBlocksStartAt--;
      }
      longerBlocksStartAt++;
  
      int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock();
      // The last elements of result may be 1 element longer;
      // first fill out as many elements as all of them have
      int rawCodewordsOffset = 0;
      for (int i = 0; i < shorterBlocksNumDataCodewords; i++) {
        for (int j = 0; j < numResultBlocks; j++) {
          result[j].codewords[i] = rawCodewords[rawCodewordsOffset++];
        }
      }
      // Fill out the last data block in the longer ones
      for (int j = longerBlocksStartAt; j < numResultBlocks; j++) {
        result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset++];
      }
      // Now add in error correction blocks
      int max = result[0].codewords.length;
      for (int i = shorterBlocksNumDataCodewords; i < max; i++) {
        for (int j = 0; j < numResultBlocks; j++) {
          int iOffset = j < longerBlocksStartAt ? i : i + 1;
          result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset++];
        }
      }
      return result;
    }