/* * 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 #include #include #include #include #include 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 T convertToBigEndian(T in); /** * Convert from the native device endianness to little endian. */ template 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 inline status_t writeHelper(const T* buf, size_t offset, size_t count); uint32_t mOffset; Output* mOutput; Endianness mEndian; }; template 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(buf[offset + i]); if ((res = mOutput->write(reinterpret_cast(&tmp), 0, size)) != OK) { return res; } mOffset += size; } break; } case LITTLE: { for (size_t i = offset; i < count; ++i) { T tmp = convertToLittleEndian(buf[offset + i]); if ((res = mOutput->write(reinterpret_cast(&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*/