1 | /* -*- tab-width: 4; -*- */ |
2 | /* vi: set sw=2 ts=4 expandtab: */ |
3 | |
4 | /* $Id: ee6f7be4d43390de78e1815ed158012c78ddeff1 $ */ |
5 | |
6 | /* |
7 | * Copyright 2010-2020 The Khronos Group Inc. |
8 | * SPDX-License-Identifier: Apache-2.0 |
9 | */ |
10 | |
11 | /** |
12 | * @internal |
13 | * @file checkheader.c |
14 | * @~English |
15 | * |
16 | * @brief Function to verify a KTX file header |
17 | * |
18 | * @author Mark Callow, HI Corporation |
19 | */ |
20 | |
21 | /* |
22 | * Author: Georg Kolling, Imagination Technology with modifications |
23 | * by Mark Callow, HI Corporation. |
24 | */ |
25 | #include <assert.h> |
26 | #include <string.h> |
27 | |
28 | #include "ktx.h" |
29 | #include "ktxint.h" |
30 | |
31 | /** |
32 | * @internal |
33 | * @~English |
34 | * @brief Check a KTX file header. |
35 | * |
36 | * As well as checking that the header identifies a KTX file, the function |
37 | * sanity checks the values and returns information about the texture in a |
38 | * struct KTX_supplementary_info. |
39 | * |
40 | * @param pHeader pointer to the KTX header to check |
41 | * @param pSuppInfo pointer to a KTX_supplementary_info structure in which to |
42 | * return information about the texture. |
43 | * |
44 | * @author Georg Kolling, Imagination Technology |
45 | * @author Mark Callow, HI Corporation |
46 | */ |
47 | |
48 | KTX_error_code (KTX_header* , |
49 | KTX_supplemental_info* pSuppInfo) |
50 | { |
51 | ktx_uint8_t identifier_reference[12] = KTX_IDENTIFIER_REF; |
52 | ktx_uint32_t max_dim; |
53 | |
54 | assert(pHeader != NULL && pSuppInfo != NULL); |
55 | |
56 | /* Compare identifier, is this a KTX file? */ |
57 | if (memcmp(pHeader->identifier, identifier_reference, 12) != 0) |
58 | { |
59 | return KTX_UNKNOWN_FILE_FORMAT; |
60 | } |
61 | |
62 | if (pHeader->endianness == KTX_ENDIAN_REF_REV) |
63 | { |
64 | /* Convert endianness of pHeader fields. */ |
65 | _ktxSwapEndian32(&pHeader->glType, 12); |
66 | |
67 | if (pHeader->glTypeSize != 1 && |
68 | pHeader->glTypeSize != 2 && |
69 | pHeader->glTypeSize != 4) |
70 | { |
71 | /* Only 8-, 16-, and 32-bit types supported so far. */ |
72 | return KTX_FILE_DATA_ERROR; |
73 | } |
74 | } |
75 | else if (pHeader->endianness != KTX_ENDIAN_REF) |
76 | { |
77 | return KTX_FILE_DATA_ERROR; |
78 | } |
79 | |
80 | /* Check glType and glFormat */ |
81 | pSuppInfo->compressed = 0; |
82 | if (pHeader->glType == 0 || pHeader->glFormat == 0) |
83 | { |
84 | if (pHeader->glType + pHeader->glFormat != 0) |
85 | { |
86 | /* either both or none of glType, glFormat must be zero */ |
87 | return KTX_FILE_DATA_ERROR; |
88 | } |
89 | pSuppInfo->compressed = 1; |
90 | } |
91 | |
92 | if (pHeader->glFormat == pHeader->glInternalformat) { |
93 | // glInternalFormat is either unsized (which is no longer and should |
94 | // never have been supported by libktx) or glFormat is sized. |
95 | return KTX_FILE_DATA_ERROR; |
96 | } |
97 | |
98 | /* Check texture dimensions. KTX files can store 8 types of textures: |
99 | 1D, 2D, 3D, cube, and array variants of these. There is currently |
100 | no GL extension for 3D array textures. */ |
101 | if ((pHeader->pixelWidth == 0) || |
102 | (pHeader->pixelDepth > 0 && pHeader->pixelHeight == 0)) |
103 | { |
104 | /* texture must have width */ |
105 | /* texture must have height if it has depth */ |
106 | return KTX_FILE_DATA_ERROR; |
107 | } |
108 | |
109 | |
110 | if (pHeader->pixelDepth > 0) |
111 | { |
112 | if (pHeader->numberOfArrayElements > 0) |
113 | { |
114 | /* No 3D array textures yet. */ |
115 | return KTX_UNSUPPORTED_TEXTURE_TYPE; |
116 | } |
117 | pSuppInfo->textureDimension = 3; |
118 | } |
119 | else if (pHeader->pixelHeight > 0) |
120 | { |
121 | pSuppInfo->textureDimension = 2; |
122 | } |
123 | else |
124 | { |
125 | pSuppInfo->textureDimension = 1; |
126 | } |
127 | |
128 | if (pHeader->numberOfFaces == 6) |
129 | { |
130 | if (pSuppInfo->textureDimension != 2) |
131 | { |
132 | /* cube map needs 2D faces */ |
133 | return KTX_FILE_DATA_ERROR; |
134 | } |
135 | } |
136 | else if (pHeader->numberOfFaces != 1) |
137 | { |
138 | /* numberOfFaces must be either 1 or 6 */ |
139 | return KTX_FILE_DATA_ERROR; |
140 | } |
141 | |
142 | /* Check number of mipmap levels */ |
143 | if (pHeader->numberOfMipLevels == 0) |
144 | { |
145 | pSuppInfo->generateMipmaps = 1; |
146 | pHeader->numberOfMipLevels = 1; |
147 | } |
148 | else |
149 | { |
150 | pSuppInfo->generateMipmaps = 0; |
151 | } |
152 | |
153 | /* This test works for arrays too because height or depth will be 0. */ |
154 | max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth); |
155 | if (max_dim < ((ktx_uint32_t)1 << (pHeader->numberOfMipLevels - 1))) |
156 | { |
157 | /* Can't have more mip levels than 1 + log2(max(width, height, depth)) */ |
158 | return KTX_FILE_DATA_ERROR; |
159 | } |
160 | |
161 | return KTX_SUCCESS; |
162 | } |
163 | |
164 | /** |
165 | * @internal |
166 | * @~English |
167 | * @brief Check a KTX2 file header. |
168 | * |
169 | * As well as checking that the header identifies a KTX 2 file, the function |
170 | * sanity checks the values and returns information about the texture in a |
171 | * struct KTX_supplementary_info. |
172 | * |
173 | * @param pHeader pointer to the KTX header to check |
174 | * @param pSuppInfo pointer to a KTX_supplementary_info structure in which to |
175 | * return information about the texture. |
176 | * |
177 | * @author Mark Callow, HI Corporation |
178 | */ |
179 | KTX_error_code (KTX_header2* , |
180 | KTX_supplemental_info* pSuppInfo) |
181 | { |
182 | // supp info is compressed, generateMipmaps and num dimensions. Don't need |
183 | // compressed as formatSize gives us that. I think the other 2 aren't needed. |
184 | ktx_uint8_t identifier_reference[12] = KTX2_IDENTIFIER_REF; |
185 | |
186 | assert(pHeader != NULL && pSuppInfo != NULL); |
187 | ktx_uint32_t max_dim; |
188 | |
189 | /* Compare identifier, is this a KTX file? */ |
190 | if (memcmp(pHeader->identifier, identifier_reference, 12) != 0) |
191 | { |
192 | return KTX_UNKNOWN_FILE_FORMAT; |
193 | } |
194 | |
195 | /* Check texture dimensions. KTX files can store 8 types of textures: |
196 | 1D, 2D, 3D, cube, and array variants of these. There is currently |
197 | no extension for 3D array textures in any 3D API. */ |
198 | if ((pHeader->pixelWidth == 0) || |
199 | (pHeader->pixelDepth > 0 && pHeader->pixelHeight == 0)) |
200 | { |
201 | /* texture must have width */ |
202 | /* texture must have height if it has depth */ |
203 | return KTX_FILE_DATA_ERROR; |
204 | } |
205 | |
206 | if (pHeader->pixelDepth > 0) |
207 | { |
208 | if (pHeader->layerCount > 0) |
209 | { |
210 | /* No 3D array textures yet. */ |
211 | return KTX_UNSUPPORTED_TEXTURE_TYPE; |
212 | } |
213 | pSuppInfo->textureDimension = 3; |
214 | } |
215 | else if (pHeader->pixelHeight > 0) |
216 | { |
217 | pSuppInfo->textureDimension = 2; |
218 | } |
219 | else |
220 | { |
221 | pSuppInfo->textureDimension = 1; |
222 | } |
223 | |
224 | if (pHeader->faceCount == 6) |
225 | { |
226 | if (pSuppInfo->textureDimension != 2) |
227 | { |
228 | /* cube map needs 2D faces */ |
229 | return KTX_FILE_DATA_ERROR; |
230 | } |
231 | } |
232 | else if (pHeader->faceCount != 1) |
233 | { |
234 | /* numberOfFaces must be either 1 or 6 */ |
235 | return KTX_FILE_DATA_ERROR; |
236 | } |
237 | |
238 | // Check number of mipmap levels |
239 | if (pHeader->levelCount == 0) |
240 | { |
241 | pSuppInfo->generateMipmaps = 1; |
242 | pHeader->levelCount = 1; |
243 | } |
244 | else |
245 | { |
246 | pSuppInfo->generateMipmaps = 0; |
247 | } |
248 | |
249 | // This test works for arrays too because height or depth will be 0. |
250 | max_dim = MAX(MAX(pHeader->pixelWidth, pHeader->pixelHeight), pHeader->pixelDepth); |
251 | if (max_dim < ((ktx_uint32_t)1 << (pHeader->levelCount - 1))) |
252 | { |
253 | // Can't have more mip levels than 1 + log2(max(width, height, depth)) |
254 | return KTX_FILE_DATA_ERROR; |
255 | } |
256 | |
257 | return KTX_SUCCESS; |
258 | |
259 | } |
260 | |