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
48KTX_error_code ktxCheckHeader1_(KTX_header* pHeader,
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 */
179KTX_error_code ktxCheckHeader2_(KTX_header2* pHeader,
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