Add byte order conversion utilities

This commit is contained in:
Dietrich Epp 2022-03-29 15:34:27 -04:00
parent 16f3764790
commit d980169ec6
4 changed files with 200 additions and 5 deletions

View File

@ -1,4 +1,4 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load("//bazel:copts.bzl", "COPTS")
cc_library(
@ -8,8 +8,20 @@ cc_library(
],
hdrs = [
"defs.h",
"endian.h",
"test.h",
],
copts = COPTS,
visibility = ["//visibility:public"],
)
cc_test(
name = "endian_test",
srcs = [
"endian_test.c",
],
copts = COPTS,
deps = [
":lib",
],
)

View File

@ -1,13 +1,59 @@
#ifndef defs_h
#define defs_h
#ifndef lib_defs_h
#define lib_defs_h
/* defs.h - common definitions. */
/*==============================================================================
Basic definitions
Target information
==============================================================================*/
/*
Note that this code does not need to be especially portable. It just runs on
Mac OS and development systems (for testing). We can assume that the
development system has GCC.
Macros we care about:
TARGET_OS_MAC OS is some Macintosh variant (broadly speaking)
TARGET_API_MAC_OS8 Targeting classic Mac OS (9.x and earlier)
TARGET_RT_LITTLE_ENDIAN Little-endian byte order
TARGET_RT_BIG_ENDIAN Big-endian byte order
*/
#if macintosh
/* Classic Mac OS. Header is part of Universal Interfaces & Carbon. */
#include <ConditionalMacros.h>
#elif __APPLE__
/* Newer apple systems, including macOS >= 10. Header is in /usr/include, or
within /usr/include inside the SDK. */
#include <TargetConditionals.h>
#else
#if __BYTE_ORDER__
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define TARGET_RT_LITTLE_ENDIAN 1
#define TARGET_RT_BIG_ENDIAN 0
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define TARGET_RT_LITTLE_ENDIAN 0
#define TARGET_RT_BIG_ENDIAN 1
#else
#error "unknown endian"
#endif
#else
#error "could not determine byte order"
#endif
#endif
/*==============================================================================
Basic types
==============================================================================*/
#if TARGET_API_MAC_OS8
#include <MacTypes.h>
#else
@ -65,7 +111,7 @@ typedef enum
Memory allocation
==============================================================================*/
#if macintosh
#if TARGET_API_MAC_OS8
#include <MacMemory.h>

75
lib/endian.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef lib_endian_h
#define lib_endian_h
/* endian.h - byte order and byte swapping */
/*
Defines macros for swapping to and from big-endian:
EndianU16_BtoN
EndianU16_NtoB
EndianU32_BtoN
EndianU32_NtoB
*/
#include "lib/defs.h"
#if TARGET_API_MAC_OS8
/* Use the legacy Mac OS header, if available. */
#include <Endian.h>
#else
/* Use the compiler built-in, if available. */
#if __clang__
#if __has_builtin(__builtin_bswap16)
#define Endian16_Swap(x) __builtin_bswap16(x)
#endif
#if __has_builtin(__builtin_bswap32)
#define Endian32_Swap(x) __builtin_bswap32(x)
#endif
#elif __GNUC__
#if __GNUC__ && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3)
#define Endian16_Swap(x) __builtin_bswap16(x)
#define Endian32_Swap(x) __builtin_bswap32(x)
#endif
#endif
/* Fallback implementations. */
/* clang-format off */
#ifndef Endian16_Swap
#define Endian16_Swap(x) \
((((UInt16)(x) << 8) & 0xff00) | \
(((UInt16)(x) >> 8) & 0x00ff))
#endif
#ifndef Endian32_Swap
#define Endian32_Swap(x) \
((((UInt32)(x) << 24) & 0xff000000) | \
(((UInt32)(x) << 8) & 0x00ff0000) | \
(((UInt32)(x) >> 8) & 0x0000ff00) | \
(((UInt32)(x) >> 24) & 0x000000ff))
#endif
/* clang-format on */
#if TARGET_RT_BIG_ENDIAN
#define EndianU16_BtoN(x) (x)
#define EndianU16_NtoB(x) (x)
#define EndianU32_BtoN(x) (x)
#define EndianU32_NtoB(x) (x)
#else
#define EndianU16_BtoN(x) Endian16_Swap(x)
#define EndianU16_NtoB(x) Endian16_Swap(x)
#define EndianU32_BtoN(x) Endian32_Swap(x)
#define EndianU32_NtoB(x) Endian32_Swap(x)
#endif
#endif /* TARGET_API_MAC_OS8 */
#endif /* lib_endian_h */

62
lib/endian_test.c Normal file
View File

@ -0,0 +1,62 @@
#include "lib/endian.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
static int gDidFail;
static void Fail(const char *name, UInt32 got, UInt32 expect)
{
fprintf(stderr, "%s = 0x%" PRIx32 ", expect 0x%" PRIx32 "\n", name, got,
expect);
gDidFail = 1;
}
#define CHECK(fn, expect) \
be = fn(u.i); \
if (be != expect) { \
Fail(#fn, be, expect); \
}
static void Test16(void)
{
union {
UInt16 i;
UInt8 b[2];
} u;
UInt16 be;
u.b[0] = 0x12;
u.b[1] = 0x34;
CHECK(EndianU16_BtoN, 0x1234)
CHECK(EndianU16_NtoB, 0x1234)
}
static void Test32(void)
{
union {
UInt32 i;
UInt8 b[2];
} u;
UInt32 be;
u.b[0] = 0x12;
u.b[1] = 0x34;
u.b[2] = 0x56;
u.b[3] = 0x78;
CHECK(EndianU32_BtoN, 0x12345678)
CHECK(EndianU32_NtoB, 0x12345678)
}
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
Test16();
Test32();
return gDidFail;
}