Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / wodim / audiosize.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)audiosize.c      1.19 04/03/01 Copyright 1998-2004 J. Schilling */
14 /*
15  *      Copyright (c) 1998-2004 J. Schilling
16  *
17  *      First .vaw implementation made by Dave Platt <dplatt@iq.nc.com>
18  *      Current .wav implementation with additional help from Heiko Eißfeld.
19  */
20 /*
21  * This program is free software; you can redistribute it and/or modify
22  * it under the terms of the GNU General Public License version 2
23  * as published by the Free Software Foundation.
24  *
25  * This program is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  * GNU General Public License for more details.
29  *
30  * You should have received a copy of the GNU General Public License along with
31  * this program; see the file COPYING.  If not, write to the Free Software
32  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33  */
34
35 #include <mconfig.h>
36 #include <statdefs.h>
37 #include <unixstd.h>
38 #include <standard.h>
39 #include <utypes.h>
40 #include <strdefs.h>
41 #include <intcvt.h>
42 #include <schily.h>
43
44 #include <usal/usalcmd.h>
45 #include "auheader.h"
46
47 typedef struct {
48         Uchar   magic[4];
49         Uchar   hdr_size[4];
50         Uchar   data_size[4];
51         Uchar   encoding[4];
52         Uchar   sample_rate[4];
53         Uchar   channels[4];
54 } sun_au_t;
55
56 #define SUN_AU_MAGIC            ".snd"
57 #define SUN_AU_UNKNOWN_LEN      ((Uint)~0)
58 #define SUN_AU_ULAW8            1               /* American ISDN Telephonie */
59 #define SUN_AU_LINEAR8          2               /* Linear PCM 8 bit/channel  */
60 #define SUN_AU_LINEAR16         3               /* Linear PCM 16 bit/channel */
61 #define SUN_AU_LINEAR24         4               /* Linear PCM 24 bit/channel */
62 #define SUN_AU_LINEAR32         5               /* Linear PCM 32 bit/channel */
63 #define SUN_AU_FLOAT            6               /* 32 bit IEEE floatingpoint */
64 #define SUN_AU_DOUBLE           7               /* 64 bit IEEE floatingpoint */
65 #define SUN_AU_G721             23              /* 4 bit CCITT G.721 ADPCM  */
66 #define SUN_AU_G722             24              /* CCITT G.722 ADPCM        */
67 #define SUN_AU_G723_3           25              /* 3 bit CCITT G.723 ADPCM  */
68 #define SUN_AU_G723_5           26              /* 5 bit CCITT G.723 ADPCM  */
69 #define SUN_AU_ALAW8            27              /* International ISDN Tel.  */
70
71 typedef struct {
72         Uchar   ckid[4];
73         Uchar   cksize[4];
74 } chunk_t;
75
76 typedef struct {
77         Uchar   wave[4];
78 } riff_chunk;
79
80 typedef struct {
81         Uchar   fmt_tag[2];
82         Uchar   channels[2];
83         Uchar   sample_rate[4];
84         Uchar   av_byte_rate[4];
85         Uchar   block_size[2];
86         Uchar   bits_per_sample[2];
87 } fmt_chunk;
88
89 #define WAV_RIFF_MAGIC          "RIFF"          /* Magic for file format    */
90 #define WAV_WAVE_MAGIC          "WAVE"          /* Magic for Waveform Audio */
91 #define WAV_FMT_MAGIC           "fmt "          /* Start of Waveform format */
92 #define WAV_DATA_MAGIC          "data"          /* Start of data chunk      */
93 #define WAV_FORMAT_PCM          0x0001          /* Linear PCM format        */
94 #define WAV_FORMAT_ULAW         0x0101          /* American ISDN Telephonie */
95 #define WAV_FORMAT_ALAW         0x0102          /* International ISDN Tel.  */
96 #define WAV_FORMAT_ADPCM        0x0103          /* ADPCM format             */
97
98 #define le_a_to_u_short(a)      ((unsigned short) \
99                                 ((((unsigned char *)a)[0]       & 0xFF) | \
100                                 (((unsigned char *)a)[1] << 8   & 0xFF00)))
101
102 #ifdef  __STDC__
103 #define le_a_to_u_long(a)       ((unsigned long) \
104                                 ((((unsigned char *)a)[0]       & 0xFF) | \
105                                 (((unsigned  char *)a)[1] << 8  & 0xFF00) | \
106                                 (((unsigned  char *)a)[2] << 16 & 0xFF0000) | \
107                                 (((unsigned  char *)a)[3] << 24 & 0xFF000000UL)))
108 #else
109 #define le_a_to_u_long(a)       ((unsigned long) \
110                                 ((((unsigned char *)a)[0]       & 0xFF) | \
111                                 (((unsigned  char *)a)[1] << 8  & 0xFF00) | \
112                                 (((unsigned  char *)a)[2] << 16 & 0xFF0000) | \
113                                 (((unsigned  char *)a)[3] << 24 & 0xFF000000)))
114 #endif
115
116 BOOL    is_auname(const char *name);
117 off_t   ausize(int f);
118 BOOL    is_wavname(const char *name);
119 off_t   wavsize(int f);
120
121 BOOL 
122 is_auname(const char *name)
123 {
124         const   char    *p;
125
126         if ((p = strrchr(name, '.')) == NULL)
127                 return (FALSE);
128         return (streql(p, ".au"));
129 }
130
131 /*
132  * Read Sun audio header, leave file seek pointer past auheader.
133  */
134 off_t 
135 ausize(int f)
136 {
137         sun_au_t        hdr;
138         struct stat     sb;
139         mode_t          mode;
140         off_t           size;
141         Int32_t         val;
142         long            ret = AU_BAD_HEADER;
143
144         /*
145          * First check if a bad guy tries to call ausize()
146          * with an unappropriate file descriptor.
147          * return -1 in this case.
148          */
149         if (isatty(f))
150                 return (-1L);
151         if (fstat(f, &sb) < 0)
152                 return (-1L);
153         mode = sb.st_mode & S_IFMT;
154         if (!S_ISREG(mode) && !S_ISBLK(mode) && !S_ISCHR(mode))
155                 return (-1L);
156
157         if (read(f, &hdr, sizeof (hdr)) != sizeof (hdr))
158                 goto err;
159
160         if (strncmp((char *)hdr.magic, SUN_AU_MAGIC, 4) != 0)
161                 goto err;
162
163         ret = AU_BAD_CODING;
164
165         val = a_to_u_4_byte(hdr.encoding);
166         if (val != SUN_AU_LINEAR16)
167                 goto err;
168
169         val = a_to_u_4_byte(hdr.channels);
170         if (val != 2)
171                 goto err;
172
173         val = a_to_u_4_byte(hdr.sample_rate);
174         if (val != 44100)
175                 goto err;
176
177         size = (off_t)a_to_u_4_byte(hdr.hdr_size);
178         if (size < (off_t)sizeof (hdr) || size > 512)
179                 goto err;
180         lseek(f, size, SEEK_SET);
181
182         /*
183          * Most .au files don't seem to honor the data_size field,
184          * so we use the whole file size without the header.
185          */
186         size = sb.st_size - size;
187         return (size);
188
189 err:
190         lseek(f, (off_t)0L, SEEK_SET);
191         return ((off_t)ret);
192 }
193
194 BOOL 
195 is_wavname(const char *name)
196 {
197         const   char    *p;
198
199         if ((p = strrchr(name, '.')) == NULL)
200                 return (FALSE);
201         return (streql(p, ".wav") || streql(p, ".WAV"));
202 }
203
204 /*
205  * Read WAV header, leave file seek pointer past WAV header.
206  */
207 off_t 
208 wavsize(int f)
209 {
210         chunk_t         chunk;
211         riff_chunk      riff;
212         fmt_chunk       fmt;
213         struct stat     sb;
214         off_t           cursor;
215         BOOL            gotFormat;
216         mode_t          mode;
217         off_t           size;
218         long            ret = AU_BAD_HEADER;
219
220         /*
221          * First check if a bad guy tries to call wavsize()
222          * with an unappropriate file descriptor.
223          * return -1 in this case.
224          */
225
226         if (isatty(f))
227                 return (-1L);
228         if (fstat(f, &sb) < 0)
229                 return (-1L);
230         mode = sb.st_mode & S_IFMT;
231         if (!S_ISREG(mode) && !S_ISBLK(mode) && !S_ISCHR(mode))
232                 return (-1L);
233
234         cursor = (off_t)0;
235         gotFormat = FALSE;
236
237         for (;;) {
238                 if (read(f, &chunk, sizeof (chunk)) != sizeof (chunk))
239                         goto err;
240                 size = (off_t)le_a_to_u_long(chunk.cksize);
241
242                 if (strncmp((char *)chunk.ckid, WAV_RIFF_MAGIC, 4) == 0) {
243                         /*
244                          * We found (first) RIFF header. Check if a WAVE
245                          * magic follows. Set up size to be able to skip
246                          * past this header.
247                          */
248                         if (read(f, &riff, sizeof (riff)) != sizeof (riff))
249                                 goto err;
250                         if (strncmp((char *)riff.wave, WAV_WAVE_MAGIC, 4) != 0)
251                                 goto err;
252                         size = (off_t)sizeof (riff);
253
254                 } else if (strncmp((char *)chunk.ckid, WAV_FMT_MAGIC, 4) == 0) {
255                         /*
256                          * We found WAVE "fmt " header. Check size (if it is
257                          * valid for a WAVE file) and coding whether it is
258                          * useable for a CD.
259                          */
260                         if (size < (off_t)sizeof (fmt)) goto err;
261                         if (sizeof (fmt) != read(f, &fmt, sizeof (fmt))) goto err;
262                         if (le_a_to_u_short(fmt.channels) != 2 ||
263                             le_a_to_u_long(fmt.sample_rate) != 44100 ||
264                             le_a_to_u_short(fmt.bits_per_sample) != 16) {
265                                 ret = AU_BAD_CODING;
266                                 goto err;
267                         }
268                         gotFormat = TRUE;
269
270                 } else if (strncmp((char *)chunk.ckid, WAV_DATA_MAGIC, 4) == 0) {
271                         /*
272                          * We found WAVE "data" header. This contains the
273                          * size value of the audio part.
274                          */
275                         if (!gotFormat) {
276                                 ret = AU_BAD_CODING;
277                                 goto err;
278                         }
279                         if ((cursor + size + sizeof (chunk)) > sb.st_size)
280                                 size = sb.st_size - (cursor  + sizeof (chunk));
281                         return (size);
282                 }
283                 cursor += size + sizeof (chunk);
284                 lseek(f, cursor, SEEK_SET);     /* Skip over current chunk */
285         }
286 err:
287         lseek(f, (off_t)0L, SEEK_SET);
288         return (ret);
289 }