We shouldn't mask the input character; instead we should do a range check before calling isprint(). Something like:
u16 uc = le16_to_cpu(in[i]); u8 c;
if (uc < 0x80 && (uc == 0 || isprint(uc))) c = uc; else c = '!';
Sounds like a good alternative to me.
Would a conversion from utf-16-le to utf-8 be a viable solution?