Skip to content

Commit 561b643

Browse files
authored
Prefer build-time endianness detection (libarchive#2464)
Endianness is easy to determine at runtime, but detecting this a single time and then reusing the cached result might require API changes. However we can use compile-time detection for some known compiler macros without API changes fairly easily. Let's start by enabling this for Clang and GCC.
1 parent 4ce9c2f commit 561b643

1 file changed

Lines changed: 27 additions & 15 deletions

File tree

libarchive/archive_string.c

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ static int archive_wstring_append_from_mbs_in_codepage(
154154
struct archive_string_conv *);
155155
static int archive_string_append_from_wcs_in_codepage(struct archive_string *,
156156
const wchar_t *, size_t, struct archive_string_conv *);
157-
static int is_big_endian(void);
158157
static int strncat_in_codepage(struct archive_string *, const void *,
159158
size_t, struct archive_string_conv *);
160159
static int win_strncat_from_utf16be(struct archive_string *, const void *,
@@ -199,6 +198,27 @@ static int archive_string_normalize_D(struct archive_string *, const void *,
199198
static int archive_string_append_unicode(struct archive_string *,
200199
const void *, size_t, struct archive_string_conv *);
201200

201+
#if defined __LITTLE_ENDIAN__
202+
#define IS_BIG_ENDIAN 0
203+
#elif defined __BIG_ENDIAN__
204+
#define IS_BIG_ENDIAN 1
205+
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
206+
#define IS_BIG_ENDIAN 0
207+
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
208+
#define IS_BIG_ENDIAN 1
209+
#else
210+
// Detect endianness at runtime.
211+
static int
212+
is_big_endian(void)
213+
{
214+
uint16_t d = 1;
215+
216+
return (archive_be16dec(&d) == 1);
217+
}
218+
219+
#define IS_BIG_ENDIAN is_big_endian()
220+
#endif
221+
202222
static struct archive_string *
203223
archive_string_append(struct archive_string *as, const char *p, size_t s)
204224
{
@@ -485,7 +505,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
485505
struct archive_string u16;
486506
int saved_flag = sc->flag;/* save current flag. */
487507

488-
if (is_big_endian())
508+
if (IS_BIG_ENDIAN)
489509
sc->flag |= SCONV_TO_UTF16BE;
490510
else
491511
sc->flag |= SCONV_TO_UTF16LE;
@@ -523,14 +543,14 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
523543
dest->length + count + 1))
524544
return (-1);
525545
wmemcpy(dest->s + dest->length, (const wchar_t *)s, count);
526-
if ((sc->flag & SCONV_FROM_UTF16BE) && !is_big_endian()) {
546+
if ((sc->flag & SCONV_FROM_UTF16BE) && !IS_BIG_ENDIAN) {
527547
uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
528548
int b;
529549
for (b = 0; b < count; b++) {
530550
uint16_t val = archive_le16dec(u16+b);
531551
archive_be16enc(u16+b, val);
532552
}
533-
} else if ((sc->flag & SCONV_FROM_UTF16LE) && is_big_endian()) {
553+
} else if ((sc->flag & SCONV_FROM_UTF16LE) && IS_BIG_ENDIAN) {
534554
uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
535555
int b;
536556
for (b = 0; b < count; b++) {
@@ -3538,7 +3558,7 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
35383558

35393559
archive_string_init(&tmp);
35403560
if (be) {
3541-
if (is_big_endian()) {
3561+
if (IS_BIG_ENDIAN) {
35423562
u16 = _p;
35433563
} else {
35443564
if (archive_string_ensure(&tmp, bytes+2) == NULL)
@@ -3551,7 +3571,7 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
35513571
u16 = tmp.s;
35523572
}
35533573
} else {
3554-
if (!is_big_endian()) {
3574+
if (!IS_BIG_ENDIAN) {
35553575
u16 = _p;
35563576
} else {
35573577
if (archive_string_ensure(&tmp, bytes+2) == NULL)
@@ -3605,14 +3625,6 @@ win_strncat_from_utf16le(struct archive_string *as, const void *_p,
36053625
return (win_strncat_from_utf16(as, _p, bytes, sc, 0));
36063626
}
36073627

3608-
static int
3609-
is_big_endian(void)
3610-
{
3611-
uint16_t d = 1;
3612-
3613-
return (archive_be16dec(&d) == 1);
3614-
}
3615-
36163628
/*
36173629
* Convert a current locale string to UTF-16BE/LE and copy the result.
36183630
* Return -1 if conversion fails.
@@ -3673,7 +3685,7 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p,
36733685
if (count == 0)
36743686
return (-1);
36753687

3676-
if (is_big_endian()) {
3688+
if (IS_BIG_ENDIAN) {
36773689
if (!bigendian) {
36783690
while (count > 0) {
36793691
uint16_t v = archive_be16dec(u16);

0 commit comments

Comments
 (0)