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