summaryrefslogtreecommitdiffstats
path: root/media/img_utils/include/img_utils/EndianUtils.h
blob: e99be1a4e376b1bda975a69a36b9a356a55774ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*
 * Copyright 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMG_UTILS_ENDIAN_UTILS
#define IMG_UTILS_ENDIAN_UTILS

#include <img_utils/Output.h>

#include <cutils/compiler.h>
#include <utils/Errors.h>
#include <stdint.h>
#include <endian.h>
#include <assert.h>

namespace android {
namespace img_utils {

/**
 * Endianness types supported.
 */
enum ANDROID_API Endianness {
    UNDEFINED_ENDIAN, // Default endianness will be used.
    BIG,
    LITTLE
};

/**
 * Convert from the native device endianness to big endian.
 */
template<typename T>
T convertToBigEndian(T in);

/**
 * Convert from the native device endianness to little endian.
 */
template<typename T>
T convertToLittleEndian(T in);

/**
 * A utility class for writing to an Output with the given endianness.
 */
class ANDROID_API EndianOutput : public Output {
    public:
        /**
         * Wrap the given Output.  Calling write methods will result in
         * writes to this output.
         */
        EndianOutput(Output* out, Endianness end=LITTLE);

        virtual ~EndianOutput();

        /**
         * Call open on the wrapped output.
         */
        virtual status_t open();

        /**
         * Call close on the wrapped output.
         */
        virtual status_t close();

        /**
         * Set the endianness to use when writing.
         */
        virtual void setEndianness(Endianness end);

        /**
         * Get the currently configured endianness.
         */
        virtual Endianness getEndianness() const;

        /**
         * Get the current number of bytes written by this EndianOutput.
         */
        virtual uint32_t getCurrentOffset() const;


        // TODO: switch write methods to uint32_t instead of size_t,
        // the max size of a TIFF files is bounded

        /**
         * The following methods will write elements from given input buffer to the output.
         * Count elements in the buffer will be written with the endianness set for this
         * EndianOutput.  If the given offset is greater than zero, that many elements will
         * be skipped in the buffer before writing.
         *
         * Returns OK on success, or a negative error code.
         */
        virtual status_t write(const uint8_t* buf, size_t offset, size_t count);

        virtual status_t write(const int8_t* buf, size_t offset, size_t count);

        virtual status_t write(const uint16_t* buf, size_t offset, size_t count);

        virtual status_t write(const int16_t* buf, size_t offset, size_t count);

        virtual status_t write(const uint32_t* buf, size_t offset, size_t count);

        virtual status_t write(const int32_t* buf, size_t offset, size_t count);

        virtual status_t write(const uint64_t* buf, size_t offset, size_t count);

        virtual status_t write(const int64_t* buf, size_t offset, size_t count);

        virtual status_t write(const float* buf, size_t offset, size_t count);

        virtual status_t write(const double* buf, size_t offset, size_t count);

    protected:
        template<typename T>
        inline status_t writeHelper(const T* buf, size_t offset, size_t count);

        uint32_t mOffset;
        Output* mOutput;
        Endianness mEndian;
};

template<typename T>
inline status_t EndianOutput::writeHelper(const T* buf, size_t offset, size_t count) {
    assert(offset <= count);
    status_t res = OK;
    size_t size = sizeof(T);
    switch(mEndian) {
        case BIG: {
            for (size_t i = offset; i < count; ++i) {
                T tmp = convertToBigEndian<T>(buf[offset + i]);
                if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size))
                        != OK) {
                    return res;
                }
                mOffset += size;
            }
            break;
        }
        case LITTLE: {
            for (size_t i = offset; i < count; ++i) {
                T tmp = convertToLittleEndian<T>(buf[offset + i]);
                if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size))
                        != OK) {
                    return res;
                }
                mOffset += size;
            }
            break;
        }
        default: {
            return BAD_VALUE;
        }
    }
    return res;
}

template<>
inline uint8_t convertToBigEndian(uint8_t in) {
    return in;
}

template<>
inline int8_t convertToBigEndian(int8_t in) {
    return in;
}

template<>
inline uint16_t convertToBigEndian(uint16_t in) {
    return htobe16(in);
}

template<>
inline int16_t convertToBigEndian(int16_t in) {
    return htobe16(in);
}

template<>
inline uint32_t convertToBigEndian(uint32_t in) {
    return htobe32(in);
}

template<>
inline int32_t convertToBigEndian(int32_t in) {
    return htobe32(in);
}

template<>
inline uint64_t convertToBigEndian(uint64_t in) {
    return htobe64(in);
}

template<>
inline int64_t convertToBigEndian(int64_t in) {
    return htobe64(in);
}

template<>
inline uint8_t convertToLittleEndian(uint8_t in) {
    return in;
}

template<>
inline int8_t convertToLittleEndian(int8_t in) {
    return in;
}

template<>
inline uint16_t convertToLittleEndian(uint16_t in) {
    return htole16(in);
}

template<>
inline int16_t convertToLittleEndian(int16_t in) {
    return htole16(in);
}

template<>
inline uint32_t convertToLittleEndian(uint32_t in) {
    return htole32(in);
}

template<>
inline int32_t convertToLittleEndian(int32_t in) {
    return htole32(in);
}

template<>
inline uint64_t convertToLittleEndian(uint64_t in) {
    return htole64(in);
}

template<>
inline int64_t convertToLittleEndian(int64_t in) {
    return htole64(in);
}

} /*namespace img_utils*/
} /*namespace android*/

#endif /*IMG_UTILS_ENDIAN_UTILS*/