Skip to content

Commit a8fbae6

Browse files
Optimize rawData QrCodeData constructor and improve input validation (#709)
1 parent 553b500 commit a8fbae6

1 file changed

Lines changed: 27 additions & 20 deletions

File tree

‎QRCoder/QRCodeData.cs‎

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public QRCodeData(string pathToRawData, Compression compressMode) : this(File.Re
5656
/// <param name="compressMode">The compression mode used for the raw data.</param>
5757
public QRCodeData(byte[] rawData, Compression compressMode)
5858
{
59-
//Decompress
59+
// Decompress
6060
if (compressMode == Compression.Deflate)
6161
{
6262
using var input = new MemoryStream(rawData);
@@ -78,46 +78,53 @@ public QRCodeData(byte[] rawData, Compression compressMode)
7878
rawData = output.ToArray();
7979
}
8080

81-
if (rawData.Length < 5)
81+
const int HeaderLength = 5; // 4 bytes signature + 1 byte side length
82+
83+
if (rawData.Length < HeaderLength)
8284
throw new InvalidDataException("Invalid raw data file. File too short.");
83-
if (rawData[0] != 0x51 || rawData[1] != 0x52 || rawData[2] != 0x52)
85+
86+
if (rawData[0] != 0x51 || rawData[1] != 0x52 || rawData[2] != 0x52 || rawData[3] != 0)
8487
throw new InvalidDataException("Invalid raw data file. Filetype doesn't match \"QRR\".");
8588

8689
// Set QR code version from side length (includes 8-module quiet zone)
87-
var sideLen = (int)rawData[4];
90+
int sideLen = rawData[4];
8891
if (sideLen < 29) // Micro QR: sideLen = 19 + 2*(m-1), m in [1..4] -> versions -1..-4
8992
{
90-
if (((sideLen - 19) & 1) != 0)
93+
if (sideLen < 19 || sideLen > 25 || (sideLen & 1) == 0)
9194
throw new InvalidDataException("Invalid raw data file. Side length not valid for Micro QR.");
92-
var m = ((sideLen - 19) / 2) + 1;
93-
Version = -m;
95+
96+
Version = -((sideLen - 17) >>> 1);
9497
}
9598
else // Standard QR: sideLen = 29 + 4*(v-1), v in [1..40]
9699
{
97-
if (((sideLen - 29) % 4) != 0)
100+
if (sideLen > 185 || (sideLen & 3) != 1)
98101
throw new InvalidDataException("Invalid raw data file. Side length not valid for QR.");
99-
Version = ((sideLen - 29) / 4) + 1;
102+
103+
Version = (sideLen - 25) >>> 2;
100104
}
101105

102-
//Unpack
103-
var modules = new Queue<bool>(8 * (rawData.Length - 5));
104-
for (int j = 5; j < rawData.Length; j++)
106+
int byteLength = (sideLen * sideLen + 7) >>> 3;
107+
if (rawData.Length < 5 + byteLength)
105108
{
106-
var b = rawData[j];
107-
for (int i = 7; i >= 0; i--)
108-
{
109-
modules.Enqueue((b & (1 << i)) != 0);
110-
}
109+
throw new InvalidDataException("Invalid raw data file. Not enough data.");
111110
}
112111

113-
//Build module matrix
112+
// Build module matrix
114113
ModuleMatrix = new List<BitArray>(sideLen);
114+
int bitIndex = HeaderLength * 8; // Skip header bytes
115+
115116
for (int y = 0; y < sideLen; y++)
116117
{
117-
ModuleMatrix.Add(new BitArray(sideLen));
118+
var row = new BitArray(sideLen);
119+
ModuleMatrix.Add(row);
120+
118121
for (int x = 0; x < sideLen; x++)
119122
{
120-
ModuleMatrix[y][x] = modules.Dequeue();
123+
int byteIndex = bitIndex >>> 3;
124+
int mask = 1 << (~bitIndex & 7);
125+
row[x] = (rawData[byteIndex] & mask) != 0;
126+
127+
bitIndex++;
121128
}
122129
}
123130

0 commit comments

Comments
 (0)