From 8da8107cc293e2aadea065ad92e082423feb83fd Mon Sep 17 00:00:00 2001 From: Project Nayuki Date: Fri, 26 Oct 2018 02:42:04 +0000 Subject: [PATCH] Updated QrCode.encodeSegments() to throw DataTooLongException - in Java, C++, Python, Rust code. Rust code also changes return types from Option to Result. Updated Java and Rust documentation. --- cpp/QrCode.cpp | 12 ++++++++++-- java/io/nayuki/qrcodegen/QrCode.java | 19 ++++++++++++------- python/qrcodegen.py | 5 ++++- rust/src/lib.rs | 28 +++++++++++++++++----------- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/cpp/QrCode.cpp b/cpp/QrCode.cpp index 842c72d..3b7f289 100644 --- a/cpp/QrCode.cpp +++ b/cpp/QrCode.cpp @@ -74,8 +74,16 @@ QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, dataUsedBits = QrSegment::getTotalBits(segs, version); if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) break; // This version number is found to be suitable - if (version >= maxVersion) // All versions in the range could not fit the given data - throw std::length_error("Data too long"); + if (version >= maxVersion) { // All versions in the range could not fit the given data + std::ostringstream sb; + if (dataUsedBits == -1) + sb << "Segment too long"; + else { + sb << "Data length = " << dataUsedBits << " bits, "; + sb << "Max capacity = " << dataCapacityBits << " bits"; + } + throw data_too_long(sb.str()); + } } if (dataUsedBits == -1) throw std::logic_error("Assertion error"); diff --git a/java/io/nayuki/qrcodegen/QrCode.java b/java/io/nayuki/qrcodegen/QrCode.java index e689955..f904a68 100644 --- a/java/io/nayuki/qrcodegen/QrCode.java +++ b/java/io/nayuki/qrcodegen/QrCode.java @@ -64,7 +64,7 @@ public final class QrCode { * @param ecl the error correction level to use (not {@code null}) (boostable) * @return a QR Code (not {@code null}) representing the text * @throws NullPointerException if the text or error correction level is {@code null} - * @throws IllegalArgumentException if the text fails to fit in the + * @throws DataTooLongException if the text fails to fit in the * largest version QR Code at the ECL, which means it is too long */ public static QrCode encodeText(String text, Ecc ecl) { @@ -84,7 +84,7 @@ public final class QrCode { * @param ecl the error correction level to use (not {@code null}) (boostable) * @return a QR Code (not {@code null}) representing the data * @throws NullPointerException if the data or error correction level is {@code null} - * @throws IllegalArgumentException if the data fails to fit in the + * @throws DataTooLongException if the data fails to fit in the * largest version QR Code at the ECL, which means it is too long */ public static QrCode encodeBinary(byte[] data, Ecc ecl) { @@ -109,7 +109,7 @@ public final class QrCode { * @param ecl the error correction level to use (not {@code null}) (boostable) * @return a QR Code (not {@code null}) representing the segments * @throws NullPointerException if the list of segments, any segment, or the error correction level is {@code null} - * @throws IllegalArgumentException if the segments fail to fit in the + * @throws DataTooLongException if the segments fail to fit in the * largest version QR Code at the ECL, which means they are too long */ public static QrCode encodeSegments(List segs, Ecc ecl) { @@ -137,8 +137,9 @@ public final class QrCode { * @return a QR Code (not {@code null}) representing the segments * @throws NullPointerException if the list of segments, any segment, or the error correction level is {@code null} * @throws IllegalArgumentException if 1 ≤ minVersion ≤ maxVersion ≤ 40 - * or −1 ≤ mask ≤ 7 is violated; or if the segments fail to - * fit in the maxVersion QR Code at the ECL, which means they are too long + * or −1 ≤ mask ≤ 7 is violated + * @throws DataTooLongException if the segments fail to fit in + * the maxVersion QR Code at the ECL, which means they are too long */ public static QrCode encodeSegments(List segs, Ecc ecl, int minVersion, int maxVersion, int mask, boolean boostEcl) { Objects.requireNonNull(segs); @@ -153,8 +154,12 @@ public final class QrCode { dataUsedBits = QrSegment.getTotalBits(segs, version); if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) break; // This version number is found to be suitable - if (version >= maxVersion) // All versions in the range could not fit the given data - throw new IllegalArgumentException("Data too long"); + if (version >= maxVersion) { // All versions in the range could not fit the given data + String msg = "Segment too long"; + if (dataUsedBits != -1) + msg = String.format("Data length = %d bits, Max capacity = %d bits", dataUsedBits, dataCapacityBits); + throw new DataTooLongException(msg); + } } assert dataUsedBits != -1; diff --git a/python/qrcodegen.py b/python/qrcodegen.py index 84c22df..b623d26 100644 --- a/python/qrcodegen.py +++ b/python/qrcodegen.py @@ -124,7 +124,10 @@ class QrCode(object): if datausedbits is not None and datausedbits <= datacapacitybits: break # This version number is found to be suitable if version >= maxversion: # All versions in the range could not fit the given data - raise ValueError("Data too long") + msg = "Segment too long" + if datausedbits is not None: + msg = "Data length = {} bits, Max capacity = {} bits".format(datausedbits, datacapacitybits) + raise DataTooLongError(msg) if datausedbits is None: raise AssertionError() diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 8f863ac..394a334 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -146,9 +146,9 @@ impl QrCode { /// QR Code version is automatically chosen for the output. The ECC level of the result may be higher than /// the ecl argument if it can be done without increasing the version. /// - /// Returns a wrapped `QrCode` if successful, or `None` if the + /// Returns a wrapped `QrCode` if successful, or `Err` if the /// data is too long to fit in any version at the given ECC level. - pub fn encode_text(text: &str, ecl: QrCodeEcc) -> Option { + pub fn encode_text(text: &str, ecl: QrCodeEcc) -> Result { let chrs: Vec = text.chars().collect(); let segs: Vec = QrSegment::make_segments(&chrs); QrCode::encode_segments(&segs, ecl) @@ -161,9 +161,9 @@ impl QrCode { /// bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. /// The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. /// - /// Returns a wrapped `QrCode` if successful, or `None` if the + /// Returns a wrapped `QrCode` if successful, or `Err` if the /// data is too long to fit in any version at the given ECC level. - pub fn encode_binary(data: &[u8], ecl: QrCodeEcc) -> Option { + pub fn encode_binary(data: &[u8], ecl: QrCodeEcc) -> Result { let segs: Vec = vec![QrSegment::make_bytes(data)]; QrCode::encode_segments(&segs, ecl) } @@ -180,9 +180,9 @@ impl QrCode { /// between modes (such as alphanumeric and byte) to encode text in less space. /// This is a mid-level API; the high-level API is `encode_text()` and `encode_binary()`. /// - /// Returns a wrapped `QrCode` if successful, or `None` if the + /// Returns a wrapped `QrCode` if successful, or `Err` if the /// data is too long to fit in any version at the given ECC level. - pub fn encode_segments(segs: &[QrSegment], ecl: QrCodeEcc) -> Option { + pub fn encode_segments(segs: &[QrSegment], ecl: QrCodeEcc) -> Result { QrCode::encode_segments_advanced(segs, ecl, QrCode_MIN_VERSION, QrCode_MAX_VERSION, None, true) } @@ -199,10 +199,10 @@ impl QrCode { /// between modes (such as alphanumeric and byte) to encode text in less space. /// This is a mid-level API; the high-level API is `encode_text()` and `encode_binary()`. /// - /// Returns a wrapped `QrCode` if successful, or `None` if the data is too + /// Returns a wrapped `QrCode` if successful, or `Err` if the data is too /// long to fit in any version in the given range at the given ECC level. pub fn encode_segments_advanced(segs: &[QrSegment], mut ecl: QrCodeEcc, - minversion: Version, maxversion: Version, mask: Option, boostecl: bool) -> Option { + minversion: Version, maxversion: Version, mask: Option, boostecl: bool) -> Result { assert!(minversion.value() <= maxversion.value(), "Invalid value"); // Find the minimal version number to use @@ -211,14 +211,20 @@ impl QrCode { loop { // Number of data bits available let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8; - if let Some(n) = QrSegment::get_total_bits(segs, version) { + let dataused: Option = QrSegment::get_total_bits(segs, version); + if let Some(n) = dataused { if n <= datacapacitybits { datausedbits = n; break; // This version number is found to be suitable } } if version.value() >= maxversion.value() { // All versions in the range could not fit the given data - return None; + let msg: String = match dataused { + None => String::from("Segment too long"), + Some(n) => format!("Data length = {} bits, Max capacity = {} bits", + n, datacapacitybits), + }; + return Err(DataTooLong(msg)); } version = Version::new(version.value() + 1); } @@ -263,7 +269,7 @@ impl QrCode { } // Create the QR Code object - Some(QrCode::encode_codewords(version, ecl, &datacodewords, mask)) + Ok(QrCode::encode_codewords(version, ecl, &datacodewords, mask)) }