1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1993-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <math.h>
34
35 #include <Audio.h>
36 #include <AudioHdr.h>
37
38 #include <parse.h>
39 #include <convert.h>
40
41 static struct keyword_table Keywords[] = {
42 (char *)"encoding", K_ENCODING,
43 (char *)"rate", K_RATE,
44 (char *)"channels", K_CHANNELS,
45 (char *)"offset", K_OFFSET,
46 (char *)"format", K_FORMAT,
47 NULL, K_NULL,
48 };
49
50 // Lookup the string in a keyword table. return the token associated with it.
51 keyword_type
do_lookup(char * s,struct keyword_table * kp)52 do_lookup(
53 char *s,
54 struct keyword_table *kp)
55 {
56 struct keyword_table *tkp = NULL;
57
58 for (; kp && kp->name; kp++) {
59 if (strncmp(s, kp->name, strlen(s)) == 0) {
60 // check if exact match
61 if (strlen(s) == strlen(kp->name)) {
62 return (kp->type);
63 } else {
64 // already have another partial match, so
65 // it's ambiguous
66 if (tkp) {
67 return (K_AMBIG);
68 } else {
69 tkp = kp;
70 }
71 }
72 }
73 }
74
75 // at end of list. if there was a partial match, return it, if
76 // not, there's no match....
77 if (tkp) {
78 return (tkp->type);
79 } else {
80 return (K_NULL);
81 }
82 }
83
84 // Parse a file format specification
85 int
fileformat_parse(char * val,format_type & format)86 fileformat_parse(
87 char *val,
88 format_type& format)
89 {
90 // XXX - other formats later ...
91 if (strcasecmp(val, "sun") == 0) {
92 format = F_SUN;
93 } else if (strcasecmp(val, "raw") == 0) {
94 format = F_RAW;
95 } else if (strcasecmp(val, "aiff") == 0) {
96 Err(MGET("AIFF not yet supported\n"));
97 return (-1);
98 } else {
99 return (-1);
100 }
101 return (0);
102 }
103
104 // Parse an audio format keyword
105 int
audioformat_parse(char * val,AudioHdr & hdr)106 audioformat_parse(
107 char *val,
108 AudioHdr& hdr)
109 {
110 // check if it's "cd" or "dat" or "voice".
111 // these set the precision and encoding, etc.
112 if (strcasecmp(val, "dat") == 0) {
113 hdr.sample_rate = 48000;
114 hdr.channels = 2;
115 hdr.encoding = LINEAR;
116 hdr.samples_per_unit = 1;
117 hdr.bytes_per_unit = 2;
118 } else if (strcasecmp(val, "cd") == 0) {
119 hdr.sample_rate = 44100;
120 hdr.channels = 2;
121 hdr.encoding = LINEAR;
122 hdr.samples_per_unit = 1;
123 hdr.bytes_per_unit = 2;
124 } else if (strcasecmp(val, "voice") == 0) {
125 hdr.sample_rate = 8000;
126 hdr.channels = 1;
127 hdr.encoding = ULAW;
128 hdr.samples_per_unit = 1;
129 hdr.bytes_per_unit = 1;
130 } else {
131 return (-1);
132 }
133 return (0);
134 }
135
136 // Parse a format spec and return an audio header that describes it.
137 // Format is in the form of: [keyword=]value[,[keyword=]value ...].
138 int
parse_format(char * s,AudioHdr & hdr,format_type & format,off_t & offset)139 parse_format(
140 char *s,
141 AudioHdr& hdr,
142 format_type& format,
143 off_t& offset)
144 {
145 char *cp;
146 char *buf;
147 char *key;
148 char *val;
149 char *cp2;
150
151 offset = 0;
152 format = F_SUN;
153
154 // if no string provided, just return ...
155 if (!(s && *s))
156 return (0);
157
158 // First off, try to parse it as a full format string
159 // (it would have to have been quoted).
160 // If this works, we're done.
161 if (hdr.FormatParse(s) == AUDIO_SUCCESS) {
162 return (0);
163 }
164
165 buf = strdup(s); // save a copy of the string
166
167 // XXX - bug alert: if someone has info="xxx,yyy", strtok will
168 // break unless we snarf properly snarf the info. punt for now,
169 // fix later (since no info supported yet)....
170
171 for (cp = strtok(buf, ","); cp; cp = strtok(NULL, ",")) {
172 // Check if there's a '='
173 // If so, left side is keyword, right side is value.
174 // If not, entire string is value.
175 if (cp2 = strchr(cp, '=')) {
176 *cp2++ = NULL;
177 key = cp;
178 val = cp2;
179
180 // Look for the keyword
181 switch (do_lookup(key, Keywords)) {
182 case K_ENCODING:
183 if (hdr.EncodingParse(val)) {
184 Err(MGET(
185 "invalid encoding option: %s\n"),
186 val);
187 goto parse_error;
188 }
189 break;
190 case K_RATE:
191 if (hdr.RateParse(val)) {
192 Err(MGET("invalid sample rate: %s\n"),
193 val);
194 goto parse_error;
195 }
196 break;
197 case K_CHANNELS:
198 if (hdr.ChannelParse(val)) {
199 Err(MGET(
200 "invalid channels option: %s\n"),
201 val);
202 goto parse_error;
203 }
204 break;
205 case K_FORMAT:
206 if (fileformat_parse(val, format) < 0) {
207 Err(MGET("unknown format: %s\n"), val);
208 goto parse_error;
209 }
210 break;
211 case K_OFFSET:
212 offset = (off_t)atoi(val);
213 break;
214 case K_AMBIG:
215 Err(MGET("ambiguous keyword: %s\n"), key);
216 goto parse_error;
217 case K_NULL:
218 Err(MGET("null keyword: =%s\n"), val);
219 goto parse_error;
220 default:
221 Err(MGET("invalid keyword: %s\n"), key);
222 goto parse_error;
223 }
224 } else {
225 // No keyword, so try to intuit the value
226 // First try encoding, audio, and file format.
227 // If they fail, try sample rate and channels.
228 val = cp;
229 if (hdr.EncodingParse(val) &&
230 (audioformat_parse(val, hdr) < 0) &&
231 (fileformat_parse(val, format) < 0)) {
232 // If this looks like sample rate, make sure
233 // it is not ambiguous with channels
234 if (!hdr.RateParse(val)) {
235 if (hdr.sample_rate < 1000) {
236 int x;
237 char y[10];
238
239 if (sscanf(val, " %lf %9s",
240 &x, y) != 1) {
241 Err(
242 MGET("ambiguous numeric option: %s\n"),
243 val);
244 goto parse_error;
245 }
246 }
247 } else if (hdr.ChannelParse(val)) {
248 Err(MGET("invalid option value: %s\n"),
249 val);
250 goto parse_error;
251 }
252 }
253 }
254 }
255 free(buf);
256 return (0);
257
258 parse_error:
259 free(buf);
260 return (-1);
261 }
262