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