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