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 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 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 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 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