Ximin Luo: > Hello liblcms2-2 maintainer, just reassigning the bug described below. > You can reproduce it with $ cd-iccdump <some test file> > > e.g. from the diffoscope source tree: > > $ cd-iccdump tests/data/test1.icc | grep 'en_US\|ne_SU' > ne_SU: sRGB [24 bytes] > [.. etc ..] > > Seems endian-related. > > Reiner Herrmann: >> On Fri, Dec 09, 2016 at 06:36:53PM +0100, Chris Lamb wrote: >>> E - ne_SU: sRGB [24 bytes] >>> E ? - - >>> E + en_US: sRGB [24 bytes] >>> E ? + + >> >> Just found out that it is caused by liblcms2-2 (2.8-2). >> After downgrading it to the version in stretch (2.7-1), everything is >> printed normally.
I think I found the cause. cmsMLUtranslationsCodes() now uses the new
strFrom16() function. The problem is that strFrom16() does not work
under little-endian systems.
static
cmsUInt16Number strTo16(const char str[3])
{
cmsUInt16Number n = ((cmsUInt16Number) str[0] << 8) | str[1];
return n; // Always big endian in this case
}
static
void strFrom16(char str[3], cmsUInt16Number n)
{
// Assiming this would be aligned
union {
cmsUInt16Number n;
char str[2];
} c;
c.n = n; // Always big endian in this case
str[0] = c.str[0]; str[1] = c.str[1]; str[2] = 0;
}
On a little-endian system strFrom16() wrongly swaps the byte order (even
though the comment says something different). You can easily test this
with the attached minimal test case (see test.c).
I think the easiest solution is the use a machine byte order independent
calculation like in strTo16(). See attached patch.
diff -u a/src/cmsnamed.c b/src/cmsnamed.c
--- a/src/cmsnamed.c
+++ b/src/cmsnamed.c
@@ -192,18 +192,10 @@
static
void strFrom16(char str[3], cmsUInt16Number n)
{
- // Assiming this would be aligned
- union {
-
- cmsUInt16Number n;
- char str[2];
-
- } c;
-
- c.n = n; // Always big endian in this case
-
- str[0] = c.str[0]; str[1] = c.str[1]; str[2] = 0;
-
+ // n is always big endian, see strTo16.
+ str[0] = (n >> 8) & 0xff;
+ str[1] = n & 0xff;
+ str[2] = 0;
}
// Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
#include <stdio.h>
#include <stdint.h>
int main() {
char s[] = "ab";
union {
uint16_t n;
char s[2];
} u;
u.n = s[0] << 8 | s[1];
printf("%c%c\n", u.s[0], u.s[1]);
}
signature.asc
Description: OpenPGP digital signature

