99 lines
3.0 KiB
Go
99 lines
3.0 KiB
Go
package decoder
|
|
|
|
import (
|
|
errors "golang.org/x/xerrors"
|
|
)
|
|
|
|
type DataBlock struct {
|
|
numDataCodewords int
|
|
codewords []byte
|
|
}
|
|
|
|
func NewDataBlock(numDataCodewords int, codewords []byte) *DataBlock {
|
|
return &DataBlock{
|
|
numDataCodewords: numDataCodewords,
|
|
codewords: codewords,
|
|
}
|
|
}
|
|
|
|
func DataBlock_GetDataBlocks(rawCodewords []byte, version *Version, ecLevel ErrorCorrectionLevel) ([]*DataBlock, error) {
|
|
if len(rawCodewords) != version.GetTotalCodewords() {
|
|
return nil, errors.Errorf(
|
|
"IllegalArgumentException: len(rawCodewords)=%v, totalCodewords=%v",
|
|
len(rawCodewords), version.GetTotalCodewords())
|
|
}
|
|
|
|
// Figure out the number and size of data blocks used by this version and
|
|
// error correction level
|
|
ecBlocks := version.GetECBlocksForLevel(ecLevel)
|
|
|
|
// First count the total number of data blocks
|
|
totalBlocks := 0
|
|
ecBlockArray := ecBlocks.GetECBlocks()
|
|
for _, ecBlock := range ecBlockArray {
|
|
totalBlocks += ecBlock.GetCount()
|
|
}
|
|
|
|
// Now establish DataBlocks of the appropriate size and number of data codewords
|
|
result := make([]*DataBlock, totalBlocks)
|
|
numResultBlocks := 0
|
|
for _, ecBlock := range ecBlockArray {
|
|
for i := 0; i < ecBlock.GetCount(); i++ {
|
|
numDataCodewords := ecBlock.GetDataCodewords()
|
|
numBlockCodewords := ecBlocks.GetECCodewordsPerBlock() + numDataCodewords
|
|
result[numResultBlocks] = NewDataBlock(numDataCodewords, make([]byte, numBlockCodewords))
|
|
numResultBlocks++
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
shorterBlocksTotalCodewords := len(result[0].codewords)
|
|
longerBlocksStartAt := len(result) - 1
|
|
for longerBlocksStartAt >= 0 {
|
|
numCodewords := len(result[longerBlocksStartAt].codewords)
|
|
if numCodewords == shorterBlocksTotalCodewords {
|
|
break
|
|
}
|
|
longerBlocksStartAt--
|
|
}
|
|
longerBlocksStartAt++
|
|
|
|
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
|
|
rawCodewordsOffset := 0
|
|
for i := 0; i < shorterBlocksNumDataCodewords; i++ {
|
|
for j := 0; j < numResultBlocks; j++ {
|
|
result[j].codewords[i] = rawCodewords[rawCodewordsOffset]
|
|
rawCodewordsOffset++
|
|
}
|
|
}
|
|
// Fill out the last data block in the longer ones
|
|
for j := longerBlocksStartAt; j < numResultBlocks; j++ {
|
|
result[j].codewords[shorterBlocksNumDataCodewords] = rawCodewords[rawCodewordsOffset]
|
|
rawCodewordsOffset++
|
|
}
|
|
// Now add in error correction blocks
|
|
max := len(result[0].codewords)
|
|
for i := shorterBlocksNumDataCodewords; i < max; i++ {
|
|
for j := 0; j < numResultBlocks; j++ {
|
|
iOffset := i
|
|
if j >= longerBlocksStartAt {
|
|
iOffset = i + 1
|
|
}
|
|
result[j].codewords[iOffset] = rawCodewords[rawCodewordsOffset]
|
|
rawCodewordsOffset++
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (this *DataBlock) GetNumDataCodewords() int {
|
|
return this.numDataCodewords
|
|
}
|
|
|
|
func (this *DataBlock) GetCodewords() []byte {
|
|
return this.codewords
|
|
}
|