diff --git a/c/qrcodegen.c b/c/qrcodegen.c index 2c5389a..2c041b7 100644 --- a/c/qrcodegen.c +++ b/c/qrcodegen.c @@ -970,10 +970,9 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz } -// Returns the number of bits needed to encode the given list of segments at the given version. -// The result is in the range [0, 32767] if successful. Otherwise, -1 is returned if any segment -// has more characters than allowed by that segment's mode's character count field at the version, -// or if the actual answer exceeds INT16_MAX. +// Calculates the number of bits needed to encode the given segments at the given version. +// Returns a non-negative number if successful. Otherwise returns -1 if a segment has too +// many characters to fit its length field, or the total bits exceeds INT16_MAX. testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) { assert(segs != NULL || len == 0); assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); @@ -985,12 +984,11 @@ testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int assert(0 <= bitLength && bitLength <= INT16_MAX); int ccbits = numCharCountBits(segs[i].mode, version); assert(0 <= ccbits && ccbits <= 16); - // Fail if segment length value doesn't fit in the length field's bit-width if (numChars >= (1L << ccbits)) - return -1; + return -1; // The segment's length doesn't fit the field's bit width result += 4L + ccbits + bitLength; if (result > INT16_MAX) - return -1; + return -1; // The sum might overflow an int type } assert(0 <= result && result <= INT16_MAX); return (int)result; diff --git a/cpp/QrSegment.cpp b/cpp/QrSegment.cpp index 3b5d509..70c0445 100644 --- a/cpp/QrSegment.cpp +++ b/cpp/QrSegment.cpp @@ -176,14 +176,13 @@ int QrSegment::getTotalBits(const vector &segs, int version) { int result = 0; for (const QrSegment &seg : segs) { int ccbits = seg.mode.numCharCountBits(version); - // Fail if segment length value doesn't fit in the length field's bit-width if (seg.numChars >= (1L << ccbits)) - return -1; + return -1; // The segment's length doesn't fit the field's bit width if (4 + ccbits > INT_MAX - result) - return -1; + return -1; // The sum will overflow an int type result += 4 + ccbits; if (seg.data.size() > static_cast(INT_MAX - result)) - return -1; + return -1; // The sum will overflow an int type result += static_cast(seg.data.size()); } return result; diff --git a/cpp/QrSegment.hpp b/cpp/QrSegment.hpp index 2b9eb66..44c74ab 100644 --- a/cpp/QrSegment.hpp +++ b/cpp/QrSegment.hpp @@ -172,7 +172,9 @@ class QrSegment final { public: const std::vector &getData() const; - // Package-private helper function. + // Calculates the number of bits needed to encode the given segments at the given version. + // Returns a non-negative number if successful. Otherwise returns -1 if a segment has too + // many characters to fit its length field, or the total bits exceeds INT_MAX. public: static int getTotalBits(const std::vector &segs, int version); diff --git a/java/io/nayuki/qrcodegen/QrSegment.java b/java/io/nayuki/qrcodegen/QrSegment.java index 8705797..281e63a 100644 --- a/java/io/nayuki/qrcodegen/QrSegment.java +++ b/java/io/nayuki/qrcodegen/QrSegment.java @@ -197,7 +197,9 @@ public final class QrSegment { } - // Package-private helper function. + // Calculates the number of bits needed to encode the given segments at the given version. + // Returns a non-negative number if successful. Otherwise returns -1 if a segment has too + // many characters to fit its length field, or the total bits exceeds Integer.MAX_VALUE. static int getTotalBits(List segs, int version) { Objects.requireNonNull(segs); if (version < 1 || version > 40) @@ -207,12 +209,11 @@ public final class QrSegment { for (QrSegment seg : segs) { Objects.requireNonNull(seg); int ccbits = seg.mode.numCharCountBits(version); - // Fail if segment length value doesn't fit in the length field's bit-width if (seg.numChars >= (1 << ccbits)) - return -1; + return -1; // The segment's length doesn't fit the field's bit width result += 4L + ccbits + seg.data.bitLength(); if (result > Integer.MAX_VALUE) - return -1; + return -1; // The sum will overflow an int type } return (int)result; } diff --git a/javascript/qrcodegen.js b/javascript/qrcodegen.js index bf3a494..b2f6e34 100644 --- a/javascript/qrcodegen.js +++ b/javascript/qrcodegen.js @@ -817,7 +817,8 @@ var qrcodegen = new function() { }; - // Package-private helper function. + // Calculates and returns the number of bits needed to encode the given segments at the given version. + // The result is infinity if a segment has too many characters to fit its length field. this.QrSegment.getTotalBits = function(segs, version) { if (version < MIN_VERSION || version > MAX_VERSION) throw "Version number out of range"; @@ -825,9 +826,8 @@ var qrcodegen = new function() { for (var i = 0; i < segs.length; i++) { var seg = segs[i]; var ccbits = seg.mode.numCharCountBits(version); - // Fail if segment length value doesn't fit in the length field's bit-width if (seg.numChars >= (1 << ccbits)) - return Infinity; + return Infinity; // The segment's length doesn't fit the field's bit width result += 4 + ccbits + seg.getBits().length; } return result; diff --git a/python/qrcodegen.py b/python/qrcodegen.py index bd2119d..49cffd4 100644 --- a/python/qrcodegen.py +++ b/python/qrcodegen.py @@ -700,7 +700,9 @@ class QrSegment(object): return list(self._bitdata) # Make defensive copy - # Package-private helper function. + # Calculates the number of bits needed to encode the given segments at the given version. + # Returns a non-negative number if successful. Otherwise returns None if a segment has + # too many characters to fit its length field. @staticmethod def get_total_bits(segs, version): if not (QrCode.MIN_VERSION <= version <= QrCode.MAX_VERSION): @@ -708,9 +710,8 @@ class QrSegment(object): result = 0 for seg in segs: ccbits = seg.get_mode().num_char_count_bits(version) - # Fail if segment length value doesn't fit in the length field's bit-width if seg.get_num_chars() >= (1 << ccbits): - return None + return None # The segment's length doesn't fit the field's bit width result += 4 + ccbits + len(seg._bitdata) return result diff --git a/rust/src/lib.rs b/rust/src/lib.rs index dc7500d..a3f651b 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -974,16 +974,18 @@ impl QrSegment { /*---- Other static functions ----*/ - // Package-private helper function. + // Calculates and returns the number of bits needed to encode the given + // segments at the given version. The result is None if a segment has too many + // characters to fit its length field, or the total bits exceeds usize::MAX. fn get_total_bits(segs: &[Self], version: Version) -> Option { let mut result: usize = 0; for seg in segs { let ccbits = seg.mode.num_char_count_bits(version); if seg.numchars >= 1 << ccbits { - return None; + return None; // The segment's length doesn't fit the field's bit width } match result.checked_add(4 + (ccbits as usize) + seg.data.len()) { - None => return None, + None => return None, // The sum will overflow a usize type Some(val) => result = val, } } diff --git a/typescript/qrcodegen.ts b/typescript/qrcodegen.ts index 596df59..08205b4 100644 --- a/typescript/qrcodegen.ts +++ b/typescript/qrcodegen.ts @@ -773,7 +773,8 @@ namespace qrcodegen { } - // Package-private helper function. + // Calculates and returns the number of bits needed to encode the given segments at the given version. + // The result is infinity if a segment has too many characters to fit its length field. public static getTotalBits(segs: Array, version: int): number { if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION) throw "Version number out of range"; @@ -781,9 +782,8 @@ namespace qrcodegen { for (let i = 0; i < segs.length; i++) { let seg: QrSegment = segs[i]; let ccbits: int = seg.mode.numCharCountBits(version); - // Fail if segment length value doesn't fit in the length field's bit-width if (seg.numChars >= (1 << ccbits)) - return Infinity; + return Infinity; // The segment's length doesn't fit the field's bit width result += 4 + ccbits + seg.getBits().length; } return result;