OLD | NEW |
(Empty) | |
| 1 |
| 2 /* |
| 3 * Copyright 2014 Google Inc. |
| 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. |
| 7 */ |
| 8 |
| 9 #include "ktx.h" |
| 10 #include "SkStream.h" |
| 11 #include "SkEndian.h" |
| 12 |
| 13 #include "gl/GrGLDefines.h" |
| 14 |
| 15 #define KTX_FILE_IDENTIFIER_SIZE 12 |
| 16 static const uint8_t KTX_FILE_IDENTIFIER[KTX_FILE_IDENTIFIER_SIZE] = { |
| 17 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A |
| 18 }; |
| 19 |
| 20 static const uint32_t kKTX_ENDIANNESS_CODE = 0x04030201; |
| 21 |
| 22 bool SkKTXFile::KeyValue::readKeyAndValue(const uint8_t* data) { |
| 23 const char *key = reinterpret_cast<const char *>(data); |
| 24 const char *value = key; |
| 25 |
| 26 size_t bytesRead = 0; |
| 27 while (*value != '\0' && bytesRead < this->fDataSz) { |
| 28 ++bytesRead; |
| 29 ++value; |
| 30 } |
| 31 |
| 32 // Error of some sort.. |
| 33 if (bytesRead >= this->fDataSz) { |
| 34 return false; |
| 35 } |
| 36 |
| 37 // Read the zero terminator |
| 38 ++bytesRead; |
| 39 ++value; |
| 40 |
| 41 size_t bytesLeft = this->fDataSz - bytesRead; |
| 42 this->fKey.set(key, bytesRead); |
| 43 if (bytesLeft > 0) { |
| 44 this->fValue.set(value, bytesLeft); |
| 45 } else { |
| 46 return false; |
| 47 } |
| 48 |
| 49 return true; |
| 50 } |
| 51 |
| 52 uint32_t SkKTXFile::readInt(const uint8_t** buf, size_t* bytesLeft) const { |
| 53 SkASSERT(NULL != buf && NULL != bytesLeft); |
| 54 |
| 55 uint32_t result; |
| 56 |
| 57 if (*bytesLeft < 4) { |
| 58 SkASSERT(false); |
| 59 return 0; |
| 60 } |
| 61 |
| 62 memcpy(&result, *buf, 4); |
| 63 *buf += 4; |
| 64 |
| 65 if (fSwapBytes) { |
| 66 SkEndianSwap32(result); |
| 67 } |
| 68 |
| 69 *bytesLeft -= 4; |
| 70 |
| 71 return result; |
| 72 } |
| 73 |
| 74 bool SkKTXFile::isETC1() const { |
| 75 return this->valid() && GR_GL_COMPRESSED_RGB8_ETC1 == fHeader.fGLInternalFor
mat; |
| 76 } |
| 77 |
| 78 bool SkKTXFile::isRGBA8() const { |
| 79 return this->valid() && GR_GL_RGBA8 == fHeader.fGLInternalFormat; |
| 80 } |
| 81 |
| 82 bool SkKTXFile::isRGB8() const { |
| 83 return this->valid() && GR_GL_RGB8 == fHeader.fGLInternalFormat; |
| 84 } |
| 85 |
| 86 bool SkKTXFile::readKTXFile(const uint8_t* data, size_t dataLen) { |
| 87 const uint8_t *buf = data; |
| 88 size_t bytesLeft = dataLen; |
| 89 |
| 90 // Make sure original KTX header is there... this should have been checked |
| 91 // already by a call to is_ktx() |
| 92 SkASSERT(bytesLeft > KTX_FILE_IDENTIFIER_SIZE); |
| 93 SkASSERT(0 == memcmp(KTX_FILE_IDENTIFIER, buf, KTX_FILE_IDENTIFIER_SIZE)); |
| 94 buf += KTX_FILE_IDENTIFIER_SIZE; |
| 95 bytesLeft -= KTX_FILE_IDENTIFIER_SIZE; |
| 96 |
| 97 // Read header, but first make sure that we have the proper space: we need |
| 98 // two 32-bit ints: 1 for endianness, and another for the mandatory image |
| 99 // size after the header. |
| 100 if (bytesLeft < 8 + sizeof(Header)) { |
| 101 return false; |
| 102 } |
| 103 |
| 104 uint32_t endianness = this->readInt(&buf, &bytesLeft); |
| 105 fSwapBytes = kKTX_ENDIANNESS_CODE != endianness; |
| 106 |
| 107 // Read header values |
| 108 fHeader.fGLType = this->readInt(&buf, &bytesLeft); |
| 109 fHeader.fGLTypeSize = this->readInt(&buf, &bytesLeft); |
| 110 fHeader.fGLFormat = this->readInt(&buf, &bytesLeft); |
| 111 fHeader.fGLInternalFormat = this->readInt(&buf, &bytesLeft); |
| 112 fHeader.fGLBaseInternalFormat = this->readInt(&buf, &bytesLeft); |
| 113 fHeader.fPixelWidth = this->readInt(&buf, &bytesLeft); |
| 114 fHeader.fPixelHeight = this->readInt(&buf, &bytesLeft); |
| 115 fHeader.fPixelDepth = this->readInt(&buf, &bytesLeft); |
| 116 fHeader.fNumberOfArrayElements = this->readInt(&buf, &bytesLeft); |
| 117 fHeader.fNumberOfFaces = this->readInt(&buf, &bytesLeft); |
| 118 fHeader.fNumberOfMipmapLevels = this->readInt(&buf, &bytesLeft); |
| 119 fHeader.fBytesOfKeyValueData = this->readInt(&buf, &bytesLeft); |
| 120 |
| 121 // Check for things that we understand... |
| 122 { |
| 123 // First, we only support compressed formats and single byte |
| 124 // representations at the moment. If the internal format is |
| 125 // compressed, the the GLType field in the header must be zero. |
| 126 // In the future, we may support additional data types (such |
| 127 // as GL_UNSIGNED_SHORT_5_6_5) |
| 128 if (fHeader.fGLType != 0 && fHeader.fGLType != GR_GL_UNSIGNED_BYTE) { |
| 129 return false; |
| 130 } |
| 131 |
| 132 // This means that for well-formatted KTX files, the glTypeSize |
| 133 // field must be one... |
| 134 if (fHeader.fGLTypeSize != 1) { |
| 135 return false; |
| 136 } |
| 137 |
| 138 // We don't support 3D textures. |
| 139 if (fHeader.fPixelDepth > 1) { |
| 140 return false; |
| 141 } |
| 142 |
| 143 // We don't support texture arrays |
| 144 if (fHeader.fNumberOfArrayElements > 1) { |
| 145 return false; |
| 146 } |
| 147 |
| 148 // We don't support cube maps |
| 149 if (fHeader.fNumberOfFaces > 1) { |
| 150 return false; |
| 151 } |
| 152 } |
| 153 |
| 154 // Make sure that we have enough bytes left for the key/value |
| 155 // data according to what was said in the header. |
| 156 if (bytesLeft < fHeader.fBytesOfKeyValueData) { |
| 157 return false; |
| 158 } |
| 159 |
| 160 // Next read the key value pairs |
| 161 size_t keyValueBytesRead = 0; |
| 162 while (keyValueBytesRead < fHeader.fBytesOfKeyValueData) { |
| 163 uint32_t keyValueBytes = this->readInt(&buf, &bytesLeft); |
| 164 keyValueBytesRead += 4; |
| 165 |
| 166 if (keyValueBytes > bytesLeft) { |
| 167 return false; |
| 168 } |
| 169 |
| 170 KeyValue kv(keyValueBytes); |
| 171 if (!kv.readKeyAndValue(buf)) { |
| 172 return false; |
| 173 } |
| 174 |
| 175 fKeyValuePairs.push_back(kv); |
| 176 |
| 177 uint32_t keyValueBytesPadded = (keyValueBytes + 3) & ~3; |
| 178 buf += keyValueBytesPadded; |
| 179 keyValueBytesRead += keyValueBytesPadded; |
| 180 bytesLeft -= keyValueBytesPadded; |
| 181 } |
| 182 |
| 183 // Read the pixel data... |
| 184 int mipmaps = SkMax32(fHeader.fNumberOfMipmapLevels, 1); |
| 185 SkASSERT(mipmaps == 1); |
| 186 |
| 187 int arrayElements = SkMax32(fHeader.fNumberOfArrayElements, 1); |
| 188 SkASSERT(arrayElements == 1); |
| 189 |
| 190 int faces = SkMax32(fHeader.fNumberOfFaces, 1); |
| 191 SkASSERT(faces == 1); |
| 192 |
| 193 int depth = SkMax32(fHeader.fPixelDepth, 1); |
| 194 SkASSERT(depth == 1); |
| 195 |
| 196 for (int mipmap = 0; mipmap < mipmaps; ++mipmap) { |
| 197 // Make sure that we have at least 4 more bytes for the first image size |
| 198 if (bytesLeft < 4) { |
| 199 return false; |
| 200 } |
| 201 |
| 202 uint32_t imgSize = this->readInt(&buf, &bytesLeft); |
| 203 |
| 204 // Truncated file. |
| 205 if (bytesLeft < imgSize) { |
| 206 return false; |
| 207 } |
| 208 |
| 209 // !FIXME! If support is ever added for cube maps then the padding |
| 210 // needs to be taken into account here. |
| 211 for (int arrayElement = 0; arrayElement < arrayElements; ++arrayElement)
{ |
| 212 for (int face = 0; face < faces; ++face) { |
| 213 for (int z = 0; z < depth; ++z) { |
| 214 PixelData pd(buf, imgSize); |
| 215 fPixelData.append(1, &pd); |
| 216 } |
| 217 } |
| 218 } |
| 219 |
| 220 uint32_t imgSizePadded = (imgSize + 3) & ~3; |
| 221 buf += imgSizePadded; |
| 222 bytesLeft -= imgSizePadded; |
| 223 } |
| 224 |
| 225 return bytesLeft == 0; |
| 226 } |
| 227 |
| 228 bool SkKTXFile::is_ktx(const uint8_t *data) { |
| 229 return 0 == memcmp(KTX_FILE_IDENTIFIER, data, KTX_FILE_IDENTIFIER_SIZE); |
| 230 } |
| 231 |
| 232 bool SkKTXFile::is_ktx(SkStreamRewindable* stream) { |
| 233 // Read the KTX header and make sure it's valid. |
| 234 unsigned char buf[KTX_FILE_IDENTIFIER_SIZE]; |
| 235 bool largeEnough = |
| 236 stream->read((void*)buf, KTX_FILE_IDENTIFIER_SIZE) == KTX_FILE_IDENTIFIE
R_SIZE; |
| 237 stream->rewind(); |
| 238 if (!largeEnough) { |
| 239 return false; |
| 240 } |
| 241 return is_ktx(buf); |
| 242 } |
OLD | NEW |