1 /*
2 * Copyright 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef IMG_UTILS_ENDIAN_UTILS
18 #define IMG_UTILS_ENDIAN_UTILS
19
20 #include <img_utils/Output.h>
21
22 #include <cutils/compiler.h>
23 #include <utils/Errors.h>
24 #include <stdint.h>
25 #include <endian.h>
26 #include <assert.h>
27
28 namespace android {
29 namespace img_utils {
30
31 /**
32 * Endianness types supported.
33 */
34 enum ANDROID_API Endianness {
35 UNDEFINED_ENDIAN, // Default endianness will be used.
36 BIG,
37 LITTLE
38 };
39
40 /**
41 * Convert from the native device endianness to big endian.
42 */
43 template<typename T>
44 T convertToBigEndian(T in);
45
46 /**
47 * Convert from the native device endianness to little endian.
48 */
49 template<typename T>
50 T convertToLittleEndian(T in);
51
52 /**
53 * A utility class for writing to an Output with the given endianness.
54 */
55 class ANDROID_API EndianOutput : public Output {
56 public:
57 /**
58 * Wrap the given Output. Calling write methods will result in
59 * writes to this output.
60 */
61 EndianOutput(Output* out, Endianness end=LITTLE);
62
63 virtual ~EndianOutput();
64
65 /**
66 * Call open on the wrapped output.
67 */
68 virtual status_t open();
69
70 /**
71 * Call close on the wrapped output.
72 */
73 virtual status_t close();
74
75 /**
76 * Set the endianness to use when writing.
77 */
78 virtual void setEndianness(Endianness end);
79
80 /**
81 * Get the currently configured endianness.
82 */
83 virtual Endianness getEndianness() const;
84
85 /**
86 * Get the current number of bytes written by this EndianOutput.
87 */
88 virtual uint32_t getCurrentOffset() const;
89
90
91 // TODO: switch write methods to uint32_t instead of size_t,
92 // the max size of a TIFF files is bounded
93
94 /**
95 * The following methods will write elements from given input buffer to the output.
96 * Count elements in the buffer will be written with the endianness set for this
97 * EndianOutput. If the given offset is greater than zero, that many elements will
98 * be skipped in the buffer before writing.
99 *
100 * Returns OK on success, or a negative error code.
101 */
102 virtual status_t write(const uint8_t* buf, size_t offset, size_t count);
103
104 virtual status_t write(const int8_t* buf, size_t offset, size_t count);
105
106 virtual status_t write(const uint16_t* buf, size_t offset, size_t count);
107
108 virtual status_t write(const int16_t* buf, size_t offset, size_t count);
109
110 virtual status_t write(const uint32_t* buf, size_t offset, size_t count);
111
112 virtual status_t write(const int32_t* buf, size_t offset, size_t count);
113
114 virtual status_t write(const uint64_t* buf, size_t offset, size_t count);
115
116 virtual status_t write(const int64_t* buf, size_t offset, size_t count);
117
118 virtual status_t write(const float* buf, size_t offset, size_t count);
119
120 virtual status_t write(const double* buf, size_t offset, size_t count);
121
122 protected:
123 template<typename T>
124 inline status_t writeHelper(const T* buf, size_t offset, size_t count);
125
126 uint32_t mOffset;
127 Output* mOutput;
128 Endianness mEndian;
129 };
130
131 template<typename T>
writeHelper(const T * buf,size_t offset,size_t count)132 inline status_t EndianOutput::writeHelper(const T* buf, size_t offset, size_t count) {
133 assert(offset <= count);
134 status_t res = OK;
135 size_t size = sizeof(T);
136 switch(mEndian) {
137 case BIG: {
138 for (size_t i = offset; i < count; ++i) {
139 T tmp = convertToBigEndian<T>(buf[offset + i]);
140 if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size))
141 != OK) {
142 return res;
143 }
144 mOffset += size;
145 }
146 break;
147 }
148 case LITTLE: {
149 for (size_t i = offset; i < count; ++i) {
150 T tmp = convertToLittleEndian<T>(buf[offset + i]);
151 if ((res = mOutput->write(reinterpret_cast<uint8_t*>(&tmp), 0, size))
152 != OK) {
153 return res;
154 }
155 mOffset += size;
156 }
157 break;
158 }
159 default: {
160 return BAD_VALUE;
161 }
162 }
163 return res;
164 }
165
166 template<>
convertToBigEndian(uint8_t in)167 inline uint8_t convertToBigEndian(uint8_t in) {
168 return in;
169 }
170
171 template<>
convertToBigEndian(int8_t in)172 inline int8_t convertToBigEndian(int8_t in) {
173 return in;
174 }
175
176 template<>
convertToBigEndian(uint16_t in)177 inline uint16_t convertToBigEndian(uint16_t in) {
178 return htobe16(in);
179 }
180
181 template<>
convertToBigEndian(int16_t in)182 inline int16_t convertToBigEndian(int16_t in) {
183 return htobe16(in);
184 }
185
186 template<>
convertToBigEndian(uint32_t in)187 inline uint32_t convertToBigEndian(uint32_t in) {
188 return htobe32(in);
189 }
190
191 template<>
convertToBigEndian(int32_t in)192 inline int32_t convertToBigEndian(int32_t in) {
193 return htobe32(in);
194 }
195
196 template<>
convertToBigEndian(uint64_t in)197 inline uint64_t convertToBigEndian(uint64_t in) {
198 return htobe64(in);
199 }
200
201 template<>
convertToBigEndian(int64_t in)202 inline int64_t convertToBigEndian(int64_t in) {
203 return htobe64(in);
204 }
205
206 template<>
convertToLittleEndian(uint8_t in)207 inline uint8_t convertToLittleEndian(uint8_t in) {
208 return in;
209 }
210
211 template<>
convertToLittleEndian(int8_t in)212 inline int8_t convertToLittleEndian(int8_t in) {
213 return in;
214 }
215
216 template<>
convertToLittleEndian(uint16_t in)217 inline uint16_t convertToLittleEndian(uint16_t in) {
218 return htole16(in);
219 }
220
221 template<>
convertToLittleEndian(int16_t in)222 inline int16_t convertToLittleEndian(int16_t in) {
223 return htole16(in);
224 }
225
226 template<>
convertToLittleEndian(uint32_t in)227 inline uint32_t convertToLittleEndian(uint32_t in) {
228 return htole32(in);
229 }
230
231 template<>
convertToLittleEndian(int32_t in)232 inline int32_t convertToLittleEndian(int32_t in) {
233 return htole32(in);
234 }
235
236 template<>
convertToLittleEndian(uint64_t in)237 inline uint64_t convertToLittleEndian(uint64_t in) {
238 return htole64(in);
239 }
240
241 template<>
convertToLittleEndian(int64_t in)242 inline int64_t convertToLittleEndian(int64_t in) {
243 return htole64(in);
244 }
245
246 } /*namespace img_utils*/
247 } /*namespace android*/
248
249 #endif /*IMG_UTILS_ENDIAN_UTILS*/
250
251