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