Example #1
0
// addPadding pads the encoded data upto the full length required.
func (q *QRCode) addPadding() {
	numDataBits := q.version.numDataBits()

	if q.data.Len() == numDataBits {
		return
	}

	// Pad to the nearest codeword boundary.
	q.data.AppendNumBools(q.version.numBitsToPadToCodeword(q.data.Len()), false)

	// Pad codewords 0b11101100 and 0b00010001.
	padding := [2]*bitset.Bitset{
		bitset.New(true, true, true, false, true, true, false, false),
		bitset.New(false, false, false, true, false, false, false, true),
	}

	// Insert pad codewords alternately.
	i := 0
	for numDataBits-q.data.Len() >= 8 {
		q.data.Append(padding[i])

		i = 1 - i // Alternate between 0 and 1.
	}

	if q.data.Len() != numDataBits {
		log.Panicf("BUG: got len %d, expected %d", q.data.Len(), numDataBits)
	}
}
Example #2
0
// encode data as one or more segments and return the encoded data.
//
// The returned data does not include the terminator bit sequence.
func (d *dataEncoder) encode(data []byte) (*bitset.Bitset, error) {
	d.data = data
	d.actual = nil
	d.optimised = nil

	if len(data) == 0 {
		return nil, errors.New("no data to encode")
	}

	// Classify data into unoptimised segments.
	d.classifyDataModes()

	// Optimise segments.
	err := d.optimiseDataModes()
	if err != nil {
		return nil, err
	}

	// Encode data.
	encoded := bitset.New()
	for _, s := range d.optimised {
		d.encodeDataRaw(s.data, s.dataMode, encoded)
	}

	return encoded, nil
}
Example #3
0
// formatInfo returns the 15-bit Format Information value for a QR
// code.
func (v qrCodeVersion) formatInfo(maskPattern int) *bitset.Bitset {
	formatID := 0

	switch v.level {
	case Low:
		formatID = 0x08 // 0b01000
	case Medium:
		formatID = 0x00 // 0b00000
	case High:
		formatID = 0x18 // 0b11000
	case Highest:
		formatID = 0x10 // 0b10000
	default:
		log.Panicf("Invalid level %d", v.level)
	}

	if maskPattern < 0 || maskPattern > 7 {
		log.Panicf("Invalid maskPattern %d", maskPattern)
	}

	formatID |= maskPattern & 0x7

	result := bitset.New()

	result.AppendUint32(formatBitSequence[formatID].regular, formatInfoLengthBits)

	return result
}
Example #4
0
func TestFormatInfo(t *testing.T) {
	tests := []struct {
		level       RecoveryLevel
		maskPattern int

		expected uint32
	}{
		{ // L=01 M=00 Q=11 H=10
			Low,
			1,
			0x72f3,
		},
		{
			Medium,
			2,
			0x5e7c,
		},
		{
			High,
			3,
			0x3a06,
		},
		{
			Highest,
			4,
			0x0762,
		},
		{
			Low,
			5,
			0x6318,
		},
		{
			Medium,
			6,
			0x4f97,
		},
		{
			High,
			7,
			0x2bed,
		},
	}

	for i, test := range tests {
		v := getQRCodeVersion(test.level, 1)

		result := v.formatInfo(test.maskPattern)

		expected := bitset.New()
		expected.AppendUint32(test.expected, formatInfoLengthBits)

		if !expected.Equals(result) {
			t.Errorf("formatInfo test #%d got %s, expected %s", i, result.String(),
				expected.String())
		}
	}
}
Example #5
0
// versionInfo returns the 18-bit Version Information value for a QR Code.
//
// Version Information is applicable only to QR Codes versions 7-40 inclusive.
// nil is returned if Version Information is not required.
func (v qrCodeVersion) versionInfo() *bitset.Bitset {
	if v.version < 7 {
		return nil
	}

	result := bitset.New()
	result.AppendUint32(versionBitSequence[v.version], 18)

	return result
}
Example #6
0
func TestSingleModeEncodings(t *testing.T) {
	tests := []struct {
		dataEncoderType dataEncoderType
		dataMode        dataMode
		data            string
		expected        *bitset.Bitset
	}{
		{
			dataEncoderType1To9,
			dataModeNumeric,
			"01234567",
			bitset.NewFromBase2String("0001 0000001000 0000001100 0101011001 1000011"),
		},
		{
			dataEncoderType1To9,
			dataModeAlphanumeric,
			"AC-42",
			bitset.NewFromBase2String("0010 000000101 00111001110 11100111001 000010"),
		},
		{
			dataEncoderType1To9,
			dataModeByte,
			"123",
			bitset.NewFromBase2String("0100 00000011 00110001 00110010 00110011"),
		},
		{
			dataEncoderType10To26,
			dataModeByte,
			"123",
			bitset.NewFromBase2String("0100 00000000 00000011 00110001 00110010 00110011"),
		},
		{
			dataEncoderType27To40,
			dataModeByte,
			"123",
			bitset.NewFromBase2String("0100 00000000 00000011 00110001 00110010 00110011"),
		},
	}

	for _, test := range tests {
		encoder := newDataEncoder(test.dataEncoderType)
		encoded := bitset.New()

		encoder.encodeDataRaw([]byte(test.data), test.dataMode, encoded)

		if !test.expected.Equals(encoded) {
			t.Errorf("For %s got %s, expected %s", test.data, encoded.String(),
				test.expected.String())
		}
	}
}
Example #7
0
// newDataEncoder constructs a dataEncoder.
func newDataEncoder(t dataEncoderType) *dataEncoder {
	d := &dataEncoder{}

	switch t {
	case dataEncoderType1To9:
		d = &dataEncoder{
			minVersion:                   1,
			maxVersion:                   9,
			numericModeIndicator:         bitset.New(b0, b0, b0, b1),
			alphanumericModeIndicator:    bitset.New(b0, b0, b1, b0),
			byteModeIndicator:            bitset.New(b0, b1, b0, b0),
			numNumericCharCountBits:      10,
			numAlphanumericCharCountBits: 9,
			numByteCharCountBits:         8,
		}
	case dataEncoderType10To26:
		d = &dataEncoder{
			minVersion:                   10,
			maxVersion:                   26,
			numericModeIndicator:         bitset.New(b0, b0, b0, b1),
			alphanumericModeIndicator:    bitset.New(b0, b0, b1, b0),
			byteModeIndicator:            bitset.New(b0, b1, b0, b0),
			numNumericCharCountBits:      12,
			numAlphanumericCharCountBits: 11,
			numByteCharCountBits:         16,
		}
	case dataEncoderType27To40:
		d = &dataEncoder{
			minVersion:                   27,
			maxVersion:                   40,
			numericModeIndicator:         bitset.New(b0, b0, b0, b1),
			alphanumericModeIndicator:    bitset.New(b0, b0, b1, b0),
			byteModeIndicator:            bitset.New(b0, b1, b0, b0),
			numNumericCharCountBits:      14,
			numAlphanumericCharCountBits: 13,
			numByteCharCountBits:         16,
		}
	default:
		log.Panic("Unknown dataEncoderType")
	}

	return d
}
Example #8
0
func TestVersionInfo(t *testing.T) {
	tests := []struct {
		version  int
		expected uint32
	}{
		{
			7,
			0x007c94,
		},
		{
			10,
			0x00a4d3,
		},
		{
			20,
			0x0149a6,
		},
		{
			30,
			0x01ed75,
		},
		{
			40,
			0x028c69,
		},
	}

	for i, test := range tests {
		var v *qrCodeVersion

		v = getQRCodeVersion(Low, test.version)

		result := v.versionInfo()

		expected := bitset.New()
		expected.AppendUint32(test.expected, versionInfoLengthBits)

		if !expected.Equals(result) {
			t.Errorf("versionInfo test #%d got %s, expected %s", i, result.String(),
				expected.String())
		}
	}
}
func TestBuildRegularSymbol(t *testing.T) {
	for k := 0; k <= 7; k++ {
		v := getQRCodeVersion(Low, 1)

		data := bitset.New()
		for i := 0; i < 26; i++ {
			data.AppendNumBools(8, false)
		}

		s, err := buildRegularSymbol(*v, k, data)

		if err != nil {
			fmt.Println(err.Error())
		} else {
			_ = s
			//fmt.Print(m.string())
		}
	}
}
Example #10
0
// encodeBlocks takes the completed (terminated & padded) encoded data, splits
// the data into blocks (as specified by the QR Code version), applies error
// correction to each block, then interleaves the blocks together.
//
// The QR Code's final data sequence is returned.
func (q *QRCode) encodeBlocks() *bitset.Bitset {
	// Split into blocks.
	type dataBlock struct {
		data          *bitset.Bitset
		ecStartOffset int
	}

	block := make([]dataBlock, q.version.numBlocks())

	start := 0
	end := 0
	blockID := 0

	for _, b := range q.version.block {
		for j := 0; j < b.numBlocks; j++ {
			start = end
			end = start + b.numDataCodewords*8

			// Apply error correction to each block.
			numErrorCodewords := b.numCodewords - b.numDataCodewords
			block[blockID].data = reedsolomon.Encode(q.data.Substr(start, end), numErrorCodewords)
			block[blockID].ecStartOffset = end - start

			blockID++
		}
	}

	// Interleave the blocks.

	result := bitset.New()

	// Combine data blocks.
	working := true
	for i := 0; working; i += 8 {
		working = false

		for j, b := range block {
			if i >= block[j].ecStartOffset {
				continue
			}

			result.Append(b.data.Substr(i, i+8))

			working = true
		}
	}

	// Combine error correction blocks.
	working = true
	for i := 0; working; i += 8 {
		working = false

		for j, b := range block {
			offset := i + block[j].ecStartOffset
			if offset >= block[j].data.Len() {
				continue
			}

			result.Append(b.data.Substr(offset, offset+8))

			working = true
		}
	}

	// Append remainder bits.
	result.AppendNumBools(q.version.numRemainderBits, false)

	return result
}