}
/**
- * @param rawFormatInfo
- * @return
+ * @param maskedFormatInfo format info indicator, with mask still applied
+ * @return information about the format it specifies, or <code>null</code>
+ * if doesn't seem to match any known pattern
*/
- static FormatInformation decodeFormatInformation(int rawFormatInfo) {
- FormatInformation formatInfo = doDecodeFormatInformation(rawFormatInfo);
+ static FormatInformation decodeFormatInformation(int maskedFormatInfo) {
+ FormatInformation formatInfo = doDecodeFormatInformation(maskedFormatInfo);
if (formatInfo != null) {
return formatInfo;
}
// Should return null, but, some QR codes apparently
- // do not mask this info. Try again, first masking the raw bits so
- // the function will unmask
- return doDecodeFormatInformation(rawFormatInfo ^ FORMAT_INFO_MASK_QR);
+ // do not mask this info. Try again by actually masking the pattern
+ // first
+ return doDecodeFormatInformation(maskedFormatInfo ^ FORMAT_INFO_MASK_QR);
}
- private static FormatInformation doDecodeFormatInformation(int rawFormatInfo) {
- // Unmask:
- int unmaskedFormatInfo = rawFormatInfo ^ FORMAT_INFO_MASK_QR;
+ private static FormatInformation doDecodeFormatInformation(int maskedFormatInfo) {
// Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing
int bestDifference = Integer.MAX_VALUE;
int bestFormatInfo = 0;
for (int i = 0; i < FORMAT_INFO_DECODE_LOOKUP.length; i++) {
int[] decodeInfo = FORMAT_INFO_DECODE_LOOKUP[i];
int targetInfo = decodeInfo[0];
- if (targetInfo == unmaskedFormatInfo) {
+ if (targetInfo == maskedFormatInfo) {
// Found an exact match
return new FormatInformation(decodeInfo[1]);
}
- int bitsDifference = numBitsDiffering(unmaskedFormatInfo, targetInfo);
+ int bitsDifference = numBitsDiffering(maskedFormatInfo, targetInfo);
if (bitsDifference < bestDifference) {
bestFormatInfo = decodeInfo[1];
bestDifference = bitsDifference;
}
}
+ // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits
+ // differing means we found a match
if (bestDifference <= 3) {
return new FormatInformation(bestFormatInfo);
}
package com.google.zxing.qrcode.decoder;
-import com.google.zxing.ReaderException;
import junit.framework.TestCase;
/**
*/
public final class FormatInformationTestCase extends TestCase {
+ private static final int MASKED_TEST_FORMAT_INFO = 0x2BED;
+ private static final int UNMASKED_TEST_FORMAT_INFO = MASKED_TEST_FORMAT_INFO ^ 0x5412;
+
public void testBitsDiffering() {
assertEquals(0, FormatInformation.numBitsDiffering(1, 1));
assertEquals(1, FormatInformation.numBitsDiffering(0, 2));
assertEquals(32, FormatInformation.numBitsDiffering(-1, 0));
}
- public void testDecode() throws ReaderException {
+ public void testDecode() {
// Normal case
- FormatInformation expected = FormatInformation.decodeFormatInformation(0x2BED ^ 0x5412);
+ FormatInformation expected = FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO);
assertEquals((byte) 0x07, expected.getDataMask());
assertEquals(ErrorCorrectionLevel.Q, expected.getErrorCorrectionLevel());
// where the code forgot the mask!
- assertEquals(expected, FormatInformation.decodeFormatInformation(0x2BED));
+ assertEquals(expected, FormatInformation.decodeFormatInformation(UNMASKED_TEST_FORMAT_INFO));
// 1,2,3,4 bits difference
- assertEquals(expected, FormatInformation.decodeFormatInformation(0x2BEF ^ 0x5412));
- assertEquals(expected, FormatInformation.decodeFormatInformation(0x2BEE ^ 0x5412));
- assertEquals(expected, FormatInformation.decodeFormatInformation(0x2BEA ^ 0x5412));
- assertNull(FormatInformation.decodeFormatInformation(0x2BE2 ^ 0x5412));
+ assertEquals(expected, FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x01));
+ assertEquals(expected, FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x03));
+ assertEquals(expected, FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x07));
+ assertNull(FormatInformation.decodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x0F));
}
}
\ No newline at end of file