[PATCH 2/4] Add unaligned UTF-16 access

From: Vladimir 'Ï-coder/phcoder' Serbinenko
Date: Thu May 31 2012 - 21:10:23 EST


Used for reading and writing UTF-16 on UDF and Joliet.

Signed-off-by: Vladimir Serbinenko <phcoder@xxxxxxxxx>
---
fs/nls/nls_base.c | 31 +++++++++++++++++++++----------
include/linux/nls.h | 4 +++-
2 files changed, 24 insertions(+), 11 deletions(-)

diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 0c1ad5b..e941a80 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -16,6 +16,7 @@
#include <linux/kmod.h>
#include <linux/spinlock.h>
#include <asm/byteorder.h>
+#include <asm/unaligned.h>

static struct nls_table default_table;
static struct nls_table *tables = &default_table;
@@ -114,7 +115,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout)
}
EXPORT_SYMBOL(utf32_to_utf8);

-static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
+static inline void put_utf16(u16 *s, unsigned c, enum utf16_endian endian)
{
switch (endian) {
default:
@@ -126,11 +127,17 @@ static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
case UTF16_BIG_ENDIAN:
*s = __cpu_to_be16(c);
break;
+ case UTF16_LITTLE_ENDIAN_UNALIGNED:
+ put_unaligned_le16 (c, s);
+ break;
+ case UTF16_BIG_ENDIAN_UNALIGNED:
+ put_unaligned_be16 (c, s);
+ break;
}
}

int utf8s_to_utf16s(const u8 *s, int inlen, enum utf16_endian endian,
- wchar_t *pwcs, int maxout)
+ wchar_t *pwcs, int maxout)
{
u16 *op;
int size;
@@ -197,15 +204,19 @@ int unicode_to_utf16s(unicode_t u, enum utf16_endian endian,
}
EXPORT_SYMBOL(unicode_to_utf16s);

-static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian)
+static inline unsigned long get_utf16(const u16 *c, enum utf16_endian endian)
{
switch (endian) {
default:
- return c;
+ return *c;
case UTF16_LITTLE_ENDIAN:
- return __le16_to_cpu(c);
+ return __le16_to_cpu(*c);
case UTF16_BIG_ENDIAN:
- return __be16_to_cpu(c);
+ return __be16_to_cpu(*c);
+ case UTF16_LITTLE_ENDIAN_UNALIGNED:
+ return get_unaligned_le16 (c);
+ case UTF16_BIG_ENDIAN_UNALIGNED:
+ return get_unaligned_be16 (c);
}
}

@@ -218,7 +229,7 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian,

op = s;
while (inlen > 0 && maxout > 0) {
- u = get_utf16(*pwcs, endian);
+ u = get_utf16(pwcs, endian);
if (!u)
break;
pwcs++;
@@ -231,7 +242,7 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian,
}
if (inlen <= 0)
break;
- v = get_utf16(*pwcs, endian);
+ v = get_utf16(pwcs, endian);
if ((v & SURROGATE_MASK) != SURROGATE_PAIR ||
!(v & SURROGATE_LOW)) {
/* Ignore character and move on */
@@ -265,7 +276,7 @@ int utf16s_to_unicode(const wchar_t *pwcs, int inlen, enum utf16_endian endian,
const wchar_t *pwcs0 = pwcs;

while (inlen > 0) {
- u = get_utf16(*pwcs, endian);
+ u = get_utf16(pwcs, endian);
if (!u)
break;
pwcs++;
@@ -277,7 +288,7 @@ int utf16s_to_unicode(const wchar_t *pwcs, int inlen, enum utf16_endian endian,
}
if (inlen <= 0)
break;
- v = get_utf16(*pwcs, endian);
+ v = get_utf16(pwcs, endian);
if ((v & SURROGATE_MASK) != SURROGATE_PAIR ||
!(v & SURROGATE_LOW)) {
/* Ignore character and move on */
diff --git a/include/linux/nls.h b/include/linux/nls.h
index 7de1765..bb35d2b 100644
--- a/include/linux/nls.h
+++ b/include/linux/nls.h
@@ -40,7 +40,9 @@ struct nls_table {
enum utf16_endian {
UTF16_HOST_ENDIAN,
UTF16_LITTLE_ENDIAN,
- UTF16_BIG_ENDIAN
+ UTF16_BIG_ENDIAN,
+ UTF16_LITTLE_ENDIAN_UNALIGNED,
+ UTF16_BIG_ENDIAN_UNALIGNED
};

/* nls_base.c */
--
1.7.10

--
Regards
Vladimir 'Ï-coder/phcoder' Serbinenko

Attachment: signature.asc
Description: OpenPGP digital signature