Otimize last bytes chunk in base41encode (#1046)
* optimize last bytes chunk
* fixup
diff --git a/src/setup_payload/Base41.cpp b/src/setup_payload/Base41.cpp
index b5acd32..4c0af79 100644
--- a/src/setup_payload/Base41.cpp
+++ b/src/setup_payload/Base41.cpp
@@ -60,7 +60,27 @@
buf_len -= kBytesChunkLen;
buf += kBytesChunkLen;
- for (int _ = 0; _ < kBase41ChunkLen; _++)
+ // This code needs to correctly convey to the decoder
+ // the length of data encoded, so normally emits 3 chars for
+ // 2 bytes.
+ // But there's a special case possible where the last
+ // two bytes would fit in exactly 2 chars.
+ // The following conditions must be met:
+ // 1. this must be the last value
+ // 2. the value doesn't fit in a single byte, if we encode a
+ // small value at the end of the encoded string with a
+ // shortened chunk, the decoder will think only one byte
+ // was encoded
+ // 3. the value can be encoded in 2 base41 chars
+ //
+ int encodeLen = kBase41ChunkLen;
+ if (buf_len == 0 && // the very last value, i.e. not an odd byte
+ (value > UINT8_MAX) && // the value wouldn't fit in one byte
+ (value < kRadix * kRadix)) // the value can be encoded with 2 base41 chars
+ {
+ encodeLen--;
+ }
+ for (int _ = 0; _ < encodeLen; _++)
{
result += codes[value % kRadix];
value /= kRadix;
diff --git a/src/setup_payload/tests/TestQRCode.cpp b/src/setup_payload/tests/TestQRCode.cpp
index 1588e42..c15ab6a 100644
--- a/src/setup_payload/tests/TestQRCode.cpp
+++ b/src/setup_payload/tests/TestQRCode.cpp
@@ -134,12 +134,10 @@
{
uint8_t input[] = { 10, 10, 10 };
+ // basic stuff
NL_TEST_ASSERT(inSuite, base41Encode(input, 0).compare("") == 0);
-
NL_TEST_ASSERT(inSuite, base41Encode(input, 1).compare("A") == 0);
-
NL_TEST_ASSERT(inSuite, base41Encode(input, 2).compare("SL1") == 0);
-
NL_TEST_ASSERT(inSuite, base41Encode(input, 3).compare("SL1A") == 0);
// test single odd byte corner conditions
@@ -152,6 +150,25 @@
input[2] = 255;
NL_TEST_ASSERT(inSuite, base41Encode(input, 3).compare("SL196") == 0);
+ // testing optimized encoding
+ // verify that we can't optimize a low value, need 3 chars
+ input[0] = 255;
+ input[1] = 0;
+ NL_TEST_ASSERT(inSuite, base41Encode(input, 2).compare("960") == 0);
+ // smallest optimized encoding, 256
+ input[0] = 256 % 256;
+ input[1] = 256 / 256;
+ NL_TEST_ASSERT(inSuite, base41Encode(input, 2).compare("A6") == 0);
+ // largest optimizated encoding value
+ input[0] = ((kRadix * kRadix) - 1) % 256;
+ input[1] = ((kRadix * kRadix) - 1) / 256;
+ NL_TEST_ASSERT(inSuite, base41Encode(input, 2).compare("..") == 0);
+ // can't optimize
+ input[0] = ((kRadix * kRadix)) % 256;
+ input[1] = ((kRadix * kRadix)) / 256;
+ NL_TEST_ASSERT(inSuite, base41Encode(input, 2).compare("001") == 0);
+
+ // fun with strings
NL_TEST_ASSERT(inSuite,
base41Encode((uint8_t *) "Hello World!", sizeof("Hello World!") - 1).compare("GHF.KGL+48-G5LGK35") == 0);
@@ -204,7 +221,7 @@
NL_TEST_ASSERT(inSuite, decoded.size() == 1 && decoded[0] == 255);
NL_TEST_ASSERT(inSuite, base41Decode("A6", decoded) == CHIP_NO_ERROR); // this is 256, needs 2 output bytes
NL_TEST_ASSERT(inSuite, decoded.size() == 2 && decoded[0] + decoded[1] * 256 == 256);
- NL_TEST_ASSERT(inSuite, base41Decode("..", decoded) == CHIP_NO_ERROR); // this is 41^2-1, or 1680, needs 2 output bytes
+ NL_TEST_ASSERT(inSuite, base41Decode("..", decoded) == CHIP_NO_ERROR); // this is (41*41)-1, or 1680, needs 2 output bytes
NL_TEST_ASSERT(inSuite, decoded.size() == 2 && decoded[0] + decoded[1] * 256 == (kRadix * kRadix) - 1);
}