diff --git a/src/futils.cpp b/src/futils.cpp index 67c910ac..5a7ea082 100644 --- a/src/futils.cpp +++ b/src/futils.cpp @@ -140,77 +140,53 @@ namespace Exiv2 { } int base64encode(const void* data_buf, size_t dataLength, char* result, size_t resultSize) { - const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - const uint8_t* data = (const uint8_t*)data_buf; - size_t resultIndex = 0; - size_t x; - uint32_t n = 0; - size_t padCount = dataLength % 3; - uint8_t n0, n1, n2, n3; - - /* increment over the length of the string, three characters at a time */ - for (x = 0; x < dataLength; x += 3) - { - /* these three 8-bit (ASCII) characters become one 24-bit number */ - n = data[x] << 16; - - if((x+1) < dataLength) - n += data[x+1] << 8; - - if((x+2) < dataLength) - n += data[x+2]; - - /* this 24-bit number gets separated into four 6-bit numbers */ - n0 = (uint8_t)(n >> 18) & 63; - n1 = (uint8_t)(n >> 12) & 63; - n2 = (uint8_t)(n >> 6) & 63; - n3 = (uint8_t)n & 63; - - /* - * if we have one byte available, then its encoding is spread - * out over two characters - */ - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = base64chars[n0]; - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = base64chars[n1]; - - /* - * if we have only two bytes available, then their encoding is - * spread out over three chars - */ - if((x+1) < dataLength) - { - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = base64chars[n2]; - } - - /* - * if we have all three bytes available, then their encoding is spread - * out over four characters - */ - if((x+2) < dataLength) - { - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = base64chars[n3]; - } - } - - /* - * create and add padding that is required if we did not have a multiple of 3 - * number of characters available - */ - if (padCount > 0) - { - for (; padCount < 3; padCount++) - { - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex++] = '='; - } - } - if(resultIndex >= resultSize) return 0; /* indicate failure: buffer too small */ - result[resultIndex] = 0; - return 1; /* indicate success */ + // https://vorbrodt.blog/2019/03/23/base64-encoding/ + const char kEncodeLookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const char kPadCharacter = '='; + std::string encoded; + encoded.reserve(((dataLength / 3) + (dataLength % 3 > 0)) * 4); + + std::uint32_t temp ; + unsigned char* b = (unsigned char*) data_buf; + + std::size_t i = 0 ; + while ( i < dataLength / 3 ) + { + temp = b[i+0] << 16; + temp += b[i+1] << 8; + temp += b[i+2]; + encoded.append(1, kEncodeLookup[(temp & 0x00FC0000) >> 18]); + encoded.append(1, kEncodeLookup[(temp & 0x0003F000) >> 12]); + encoded.append(1, kEncodeLookup[(temp & 0x00000FC0) >> 6 ]); + encoded.append(1, kEncodeLookup[(temp & 0x0000003F) ]); + i++ ; + } + + switch(dataLength % 3) + { + case 1: + temp = b[i+0] << 16; + encoded.append(1, kEncodeLookup[(temp & 0x00FC0000) >> 18]); + encoded.append(1, kEncodeLookup[(temp & 0x0003F000) >> 12]); + encoded.append(2, kPadCharacter); + break; + case 2: + temp = b[i+0] << 16; + temp += b[i+1] << 8; + encoded.append(1, kEncodeLookup[(temp & 0x00FC0000) >> 18]); + encoded.append(1, kEncodeLookup[(temp & 0x0003F000) >> 12]); + encoded.append(1, kEncodeLookup[(temp & 0x00000FC0) >> 6 ]); + encoded.append(1, kPadCharacter); + break; + } + size_t length = encoded.size(); + int rc = length < resultSize ? 1 : 0; + if (rc) { + ::memcpy(result,encoded.c_str(),length); + result[length]=0; + } + + return rc; } // base64encode long base64decode(const char *in, char *out, size_t out_size) { diff --git a/tests/bugfixes/github/test_pr1475_HEIC.py b/tests/bugfixes/github/test_pr1475_HEIC.py index 464cedd0..daaab50b 100644 --- a/tests/bugfixes/github/test_pr1475_HEIC.py +++ b/tests/bugfixes/github/test_pr1475_HEIC.py @@ -160,19 +160,19 @@ Exiv2::BmffImage::boxHandler: meta 36->3380 3392 | 16 | ID | 51 | 20901, 2364 Exiv2::BMFF Exif: ID = 51 from,length = 20901,2364 Exiv2::BmffImage::boxHandler: mdat 3416->1 -""","","""data:AAACLGFwcGwEAAAAbW50clJHQiBYWVogB+EABwAHAA0AFgAgYWNzcEF -QUEwAAAAAQVBQTAAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1hcHBsyhq -VgiV/EE04mRPV0eoVggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -KZGVzYwAAAPwAAABlY3BydAAAAWQAAAAjd3RwdAAAAYgAAAAUclhZWgAAAZw -AAAAUZ1hZWgAAAbAAAAAUYlhZWgAAAcQAAAAUclRSQwAAAdgAAAAgY2hhZAA -AAfgAAAAsYlRSQwAAAdgAAAAgZ1RSQwAAAdgAAAAgZGVzYwAAAAAAAAALRGl -zcGxheSBQMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB -0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBJbmMuLCAyMDE3AABYWVogAAAAAAA -A81EAAQAAAAEWzFhZWiAAAAAAAACD3wAAPb////+7WFlaIAAAAAAAAEq/AAC -xNwAACrlYWVogAAAAAAAAKDgAABELAADIuXBhcmEAAAAAAAMAAAACZmYAAPK -nAAANWQAAE9AAAApbc2YzMgAAAAAAAQxCAAAF3v//8yYAAAeTAAD9kP//+6L -///2jAAAD3AAAwG4AAAAAAAAAAA== +""","","""data:AAACAAIsAixhLGFwYXBwcHBscGwEbAQABAAAAAAAAABtAG1ubW50bnR +ydHJSclJHUkdCR0IgQiBYIFhZWFlaWVogWiAHIAfhB+EA4QAHAAcABwAHAAc +ABwANAA0ADQAWABYAFgAgACBhIGFjYWNzY3Nwc3BBcEFQQVBQUFBMUEwATAA +AAAAAAAAAAABBAEFQQVBQUFBMUEwATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2APbW9tYA1gABAAEAAQA +AAAAAAAAAAADTANMt0y1hLWFwYXBwcHBscGzKbMoayhqVGpWClYIlgiV/JX8 +QfxBNEE04TTiZOJkTmRPVE9XR1dHq0eoV6hWCFYIAggAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAApkCmRlZGVzZXN +jc2MAYwAAAAAAAAD8APwA/AAAAAAAAABlAGVjZWNwY3BycHJ0cnQAdAAAAAA +BAAFkAWQAZAAAAAAAAAAjACN3I3d0d3RwdHB0cHQAdAAAAAABAAGIAYgAiAA +AAAAAAAAUABRyFHJYclhZWFlaWVoAWgAAAAABAAGcAZwAnAAAAAAAAAAUABR +nFGdYZ1hZWFlaWVoAWgAAAAABAA== """] class pr_1475_IMG_3578_heic(metaclass=system_tests.CaseMeta): @@ -328,19 +328,19 @@ Exiv2::BmffImage::boxHandler: meta 32->3380 3388 | 16 | ID | 51 | 8907, 2024 Exiv2::BMFF Exif: ID = 51 from,length = 8907,2024 Exiv2::BmffImage::boxHandler: mdat 3412->1 -""","","""data:AAACLGFwcGwEAAAAbW50clJHQiBYWVogB+EABwAHAA0AFgAgYWNzcEF -QUEwAAAAAQVBQTAAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA0y1hcHBsyhq -VgiV/EE04mRPV0eoVggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -KZGVzYwAAAPwAAABlY3BydAAAAWQAAAAjd3RwdAAAAYgAAAAUclhZWgAAAZw -AAAAUZ1hZWgAAAbAAAAAUYlhZWgAAAcQAAAAUclRSQwAAAdgAAAAgY2hhZAA -AAfgAAAAsYlRSQwAAAdgAAAAgZ1RSQwAAAdgAAAAgZGVzYwAAAAAAAAALRGl -zcGxheSBQMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB -0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBJbmMuLCAyMDE3AABYWVogAAAAAAA -A81EAAQAAAAEWzFhZWiAAAAAAAACD3wAAPb////+7WFlaIAAAAAAAAEq/AAC -xNwAACrlYWVogAAAAAAAAKDgAABELAADIuXBhcmEAAAAAAAMAAAACZmYAAPK -nAAANWQAAE9AAAApbc2YzMgAAAAAAAQxCAAAF3v//8yYAAAeTAAD9kP//+6L -///2jAAAD3AAAwG4AAAAAAAAAAA== +""","","""data:AAACAAIsAixhLGFwYXBwcHBscGwEbAQABAAAAAAAAABtAG1ubW50bnR +ydHJSclJHUkdCR0IgQiBYIFhZWFlaWVogWiAHIAfhB+EA4QAHAAcABwAHAAc +ABwANAA0ADQAWABYAFgAgACBhIGFjYWNzY3Nwc3BBcEFQQVBQUFBMUEwATAA +AAAAAAAAAAABBAEFQQVBQUFBMUEwATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2APbW9tYA1gABAAEAAQA +AAAAAAAAAAADTANMt0y1hLWFwYXBwcHBscGzKbMoayhqVGpWClYIlgiV/JX8 +QfxBNEE04TTiZOJkTmRPVE9XR1dHq0eoV6hWCFYIAggAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAApkCmRlZGVzZXN +jc2MAYwAAAAAAAAD8APwA/AAAAAAAAABlAGVjZWNwY3BycHJ0cnQAdAAAAAA +BAAFkAWQAZAAAAAAAAAAjACN3I3d0d3RwdHB0cHQAdAAAAAABAAGIAYgAiAA +AAAAAAAAUABRyFHJYclhZWFlaWVoAWgAAAAABAAGcAZwAnAAAAAAAAAAUABR +nFGdYZ1hZWFlaWVoAWgAAAAABAA== """] class pr_1475_Stonehenge_heic(metaclass=system_tests.CaseMeta):