1 /* header.c
2 * Functions to parse Wav and Kexis file headers.
3 * Copyright (C) 2000 Wayde Milas (wmilas@rarcoa.com)
4 *
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include "types.h"
24 #include "header.h"
25 #include "kexis.h"
26
parse_kexis_header(KEXISHEADER * kexisHead,OPTIONSTRUCT * options)27 void parse_kexis_header(KEXISHEADER *kexisHead, OPTIONSTRUCT *options)
28 {
29 int length;
30
31 length = fread(kexisHead, sizeof(KEXISHEADER), 1, options->inFileStream);
32 if(length!= 1) {
33 sprintf(options->errorString,
34 "This file is not long enough to contain a Kexis header!");
35 handle_error(options);
36 }
37
38 if(strncmp("KEXS", kexisHead->kexisID, 4) != 0) {
39 sprintf(options->errorString, "File does not contain a KEXS header!");
40 handle_error(options);
41 }
42 else if(kexisHead->encoderVersion <= 0 ||
43 kexisHead->encoderVersion > MAX_STANDARD_ENCODER) {
44 sprintf(options->errorString, "Invalid Encoder Version: %hd.",
45 kexisHead->encoderVersion);
46 handle_error(options);
47 }
48 else if(kexisHead->predictorVersion <= 0 ||
49 kexisHead->predictorVersion > MAX_STANDARD_PREDICTOR) {
50 sprintf(options->errorString, "Invalid Predictor Version: %hd.",
51 kexisHead->predictorVersion);
52 handle_error(options);
53 }
54 else if(kexisHead->kHistorySize < 1 ||
55 kexisHead->kHistorySize > MAX_KHISTORY) {
56 sprintf(options->errorString, "Invalid K History Size: %hd.",
57 kexisHead->kHistorySize);
58 handle_error(options);
59 }
60 else if(kexisHead->frameSize < 64) {
61 if(kexisHead->predictorVersion == FRAME_PREDICTOR) {
62 sprintf(options->errorString, "Invalid Frame Size: %ld.",
63 kexisHead->frameSize);
64 handle_error(options);
65 }
66 kexisHead->frameSize = FRAME_UNITS;
67 }
68 else if(kexisHead->options > 1) {
69 sprintf(options->errorString, "Invalid Stereo Option: %d.",
70 kexisHead->options);
71 handle_error(options);
72 }
73
74 options->encoderVersion = kexisHead->encoderVersion;
75 options->predictorVersion = kexisHead->predictorVersion;
76 options->kHistorySize = kexisHead->kHistorySize;
77 options->frameSize = kexisHead->frameSize;
78 options->joint = kexisHead->options;
79
80 if(options->displayHeader && !options->dec_stdout) {
81 printf("Kexis File Header:\n");
82 printf(" KEXS Header : %c%c%c%c\n",
83 kexisHead->kexisID[0], kexisHead->kexisID[1], kexisHead->kexisID[2],
84 kexisHead->kexisID[3]);
85 printf(" Kexis Header Version : %hd\n", kexisHead->headerVersion);
86 printf(" Encoder Version : %hd\n",
87 kexisHead->encoderVersion);
88 printf(" Predictor Version : %hd\n",
89 kexisHead->predictorVersion-1);
90 printf(" Length of Data Block : %lu\n", kexisHead->dataLength);
91 printf(" K History Size : %hd\n",
92 kexisHead->kHistorySize);
93 printf(" Use Stereo Data for Comp : %d\n", kexisHead->options);
94 printf(" Frame Size : %ld\n", kexisHead->frameSize);
95 printf("\n");
96 }
97 }
98
create_kexis_header(KEXISHEADER * kexisHeader,OPTIONSTRUCT * options,unsigned long length)99 void create_kexis_header(KEXISHEADER *kexisHeader, OPTIONSTRUCT *options,
100 unsigned long length)
101 {
102 strncpy(kexisHeader->kexisID, "KEXS", 4);
103 kexisHeader->headerVersion = CURRENT_KEXIS_HEADER;
104 kexisHeader->encoderVersion = options->encoderVersion;
105 kexisHeader->predictorVersion = options->predictorVersion;
106 kexisHeader->dataLength = length;
107 kexisHeader->kHistorySize = options->kHistorySize;
108 kexisHeader->frameSize = options->frameSize;
109 kexisHeader->options = options->joint;
110 kexisHeader->pad3 = 0;
111 }
112
parse_wave_header(WAVHEADER * wavHead,OPTIONSTRUCT * options)113 void parse_wave_header(WAVHEADER *wavHead, OPTIONSTRUCT *options)
114 {
115 int length;
116 unsigned long hold;
117
118 length = fread(wavHead->ckID, sizeof(char)*4, 1, options->inFileStream);
119 if(strncmp("RIFF", wavHead->ckID, 4) != 0 || length != 1) {
120 sprintf(options->errorString, "File does not contain a RIFF header!");
121 handle_error(options);
122 }
123
124 length = fread(&wavHead->ckSize, sizeof(unsigned long), 1,
125 options->inFileStream);
126 length = fread(wavHead->wave_ckID, sizeof(char)*4, 1, options->inFileStream);
127 if(strncmp("WAVE", wavHead->wave_ckID, 4) != 0 || length != 1) {
128 sprintf(options->errorString, "File does not contain a WAVE Header!");
129 handle_error(options);
130 }
131
132 length = fread(wavHead->fmt_ckID, sizeof(char)*4, 1, options->inFileStream);
133 // Suck bits till we hit the fmt chunk
134 while ((strncmp("fmt ", wavHead->fmt_ckID, 4) != 0) && length == 1) {
135 length = fread(&hold, sizeof(unsigned long), 1, options->inFileStream);
136 fseek(options->inFileStream, hold, SEEK_CUR);
137 length = fread(wavHead->fmt_ckID, sizeof(char)*4, 1, options->inFileStream);
138 }
139 if(length <= 0) {
140 sprintf(options->errorString,
141 "Could not find the fmt chunk in the WAV header!");
142 handle_error(options);
143 }
144
145 length = fread(&wavHead->fmt_ckSize, sizeof(unsigned long), 1,
146 options->inFileStream);
147 length = fread(&wavHead->formatTag, sizeof(unsigned short), 1,
148 options->inFileStream);
149 if(wavHead->formatTag != 1 || length != 1) {
150 sprintf(options->errorString, "WAV file contains non PCM data!");
151 handle_error(options);
152 }
153
154 length = fread(&wavHead->nChannels, sizeof(unsigned short), 1,
155 options->inFileStream);
156 if(wavHead->nChannels != 2 || length != 1) {
157 sprintf(options->errorString,
158 "This is a Mono WAV file. Hexis can only compress stereo files.");
159 handle_error(options);
160 }
161
162 length = fread(&wavHead->nSamplesPerSec, sizeof(unsigned long), 1,
163 options->inFileStream);
164 if(wavHead->nSamplesPerSec != 44100 || length != 1) {
165 sprintf(options->errorString,
166 "Kexis can only compress 44100 hz WAV Files. This one is %lu hz.",
167 wavHead->nSamplesPerSec);
168 handle_error(options);
169 }
170
171 length = fread(&wavHead->nAvgBytesPerSec, sizeof(unsigned long), 1,
172 options->inFileStream);
173 length = fread(&wavHead->nBlockAlign, sizeof(unsigned short), 1,
174 options->inFileStream);
175
176 length = fread(&wavHead->nBitsPerSample, sizeof(unsigned short), 1,
177 options->inFileStream);
178 if(wavHead->nBitsPerSample != 16 || length != 1) {
179 sprintf(options->errorString,
180 "Kexis can only compress 16 bit data files. This one is %ld bits.",
181 wavHead->data_ckSize);
182 handle_error(options);
183 }
184
185 length = fread(wavHead->data_ckID, sizeof(char)*4, 1, options->inFileStream);
186 // suck bits till we hit the data chunk
187 while (strncmp("data", wavHead->data_ckID, 4) != 0 && length == 1) {
188 length = fread(&hold, sizeof(unsigned long), 1, options->inFileStream);
189 fseek(options->inFileStream, hold, SEEK_CUR);
190 length = fread(wavHead->data_ckID, sizeof(char)*4, 1,
191 options->inFileStream);
192 }
193 if(length <= 0) {
194 sprintf(options->errorString,
195 "Could not find the data chunk in the WAV header!");
196 handle_error(options);
197 }
198
199 length = fread(&wavHead->data_ckSize, sizeof(unsigned long), 1,
200 options->inFileStream);
201 if(wavHead->data_ckSize <= 0) {
202 sprintf(options->errorString, "WAV file contains NO PCM data!");
203 handle_error(options);
204 }
205
206 if(options->displayHeader) {
207 printf("Wave File Header:\n");
208 printf(" RIFF Header : %c%c%c%c\n",
209 wavHead->ckID[0], wavHead->ckID[1], wavHead->ckID[2], wavHead->ckID[3]);
210 printf(" File length (minus 8 bytes) : %lu bytes\n", wavHead->ckSize);
211 printf(" RIFF Type : %c%c%c%c\n",
212 wavHead->wave_ckID[0], wavHead->wave_ckID[1], wavHead->wave_ckID[2],
213 wavHead->wave_ckID[3]);
214 printf(" Next chunk (should be fmt) : %c%c%c%c\n",
215 wavHead->fmt_ckID[0], wavHead->fmt_ckID[1], wavHead->fmt_ckID[2],
216 wavHead->fmt_ckID[3]);
217 printf(" Length of fmt data : %lu bytes\n", wavHead->fmt_ckSize);
218 printf(" Format tag (1 = PCM) : %hd\n", wavHead->formatTag);
219 printf(" Number of Channels : %hd\n", wavHead->nChannels);
220 printf(" Sapmpes per second (hz) : %lu\n", wavHead->nSamplesPerSec);
221 printf(" Average Bytes per Second\n");
222 printf(" Sample Rate * Block Align : %lu\n", wavHead->nAvgBytesPerSec);
223 printf(" Block Align\n");
224 printf(" Channels * Bits/Sample / 8 : %hd\n", wavHead->nBlockAlign);
225 printf(" Bits Per Sample : %hd\n", wavHead->nBitsPerSample);
226 printf(" Next chunk (should be data) : %c%c%c%c\n",
227 wavHead->data_ckID[0], wavHead->data_ckID[1], wavHead->data_ckID[2],
228 wavHead->data_ckID[3]);
229 printf(" Length of Data Block : %lu\n\n", wavHead->data_ckSize);
230 }
231 }
232
create_wave_header(WAVHEADER * wavHeader,unsigned long length)233 void create_wave_header(WAVHEADER *wavHeader, unsigned long length)
234 {
235 strncpy(wavHeader->ckID, "RIFF", 4);
236 wavHeader->ckSize = length+36;
237 strncpy(wavHeader->wave_ckID, "WAVE", 4);
238 strncpy(wavHeader->fmt_ckID, "fmt ", 4);
239 wavHeader->fmt_ckSize = 16;
240 wavHeader->formatTag = 1;
241 wavHeader->nChannels = 2;
242 wavHeader->nSamplesPerSec = 44100;
243 wavHeader->nAvgBytesPerSec = 176400;
244 wavHeader->nBlockAlign = 4;
245 wavHeader->nBitsPerSample = 16;
246 strncpy(wavHeader->data_ckID, "data", 4);
247 wavHeader->data_ckSize = length;
248 }
249