vfs: check userland buffers before reading them.
[haiku.git] / src / bin / play.cpp
blob4f89c7fcbb45b31d99aae0532ca5175824688e26
1 /* ++++++++++
2 play.cpp
3 Copyright (C) 1995 Be Incorporated. All Rights Reserved.
5 modified on November 03, 2003 by Jerome Duval
6 +++++ */
7 /*
8 * was released as sample code; source:
9 * ftp://planetmirror.com/raid/13/beos/samples/media_kit/obsolete/play.cpp
12 #include <errno.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <scsi.h>
17 #include <unistd.h>
18 #include <Directory.h>
19 #include <Entry.h>
20 #include <Path.h>
23 /* ----------
24 play requested track
25 ----- */
27 void
28 play(int id, scsi_play_track *track)
30 track->start_index = 1;
31 track->end_track = 99;
32 track->end_index = 1;
33 if (!ioctl(id, B_SCSI_PLAY_TRACK, track))
34 printf("Playing audio...\n");
35 else
36 printf("Play audio failed\n");
40 /* ----------
41 show valid cd-rom id's
42 (from /boot/optional/sample-code/interface_kit/CDButton/CDEngine.cpp)
43 ----- */
45 static void
46 try_dir(const char *directory, long *count, bool show)
48 bool add = false;
49 BDirectory dir;
50 dir.SetTo(directory);
51 if(dir.InitCheck() != B_NO_ERROR) {
52 return;
54 dir.Rewind();
55 BEntry entry;
56 while(dir.GetNextEntry(&entry) >= 0) {
57 BPath path;
58 const char *name;
59 entry_ref e;
61 if(entry.GetPath(&path) != B_NO_ERROR)
62 continue;
63 name = path.Path();
65 if(entry.GetRef(&e) != B_NO_ERROR)
66 continue;
68 if(entry.IsDirectory()) {
69 if(strcmp(e.name, "floppy") == 0)
70 continue; // ignore floppy (it is not silent)
71 try_dir(name, count, show);
73 else {
74 int devfd;
75 device_geometry g;
77 if(strcmp(e.name, "raw") != 0)
78 continue; // ignore partitions
80 devfd = open(name, O_RDONLY);
81 if(devfd < 0)
82 continue;
84 if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) {
85 if(g.device_type == B_CD)
87 add = true;
90 close(devfd);
92 if (add) {
93 *count += 1;
94 if (show)
95 printf(" %s\n", name);
100 /* ----------
101 show valid cd-rom id's
102 ----- */
104 int count_ids(bool show)
106 long count = 0;
108 try_dir("/dev/disk", &count, show);
109 return (count);
113 /* ----------
114 main
115 ----- */
118 main (int argc, char **argv)
120 int id;
121 int i;
122 int length;
123 int start;
124 long command;
125 long req_track = 0;
126 long vol;
127 long index;
128 ulong frames;
129 short tmp;
130 uchar *buf;
131 scsi_toc toc;
132 scsi_play_track track;
133 scsi_volume volume;
134 scsi_position position;
135 scsi_read_cd read_cd;
136 scsi_scan scan;
137 FILE *f;
139 length = count_ids(FALSE);
140 if (!length) {
141 printf("No CD-ROM drive present.\n");
142 return 0;
144 errno = 0;
146 if (argc > 2)
147 command = strtol (argv[2], 0, 0);
148 else
149 command = 0;
151 if ((argc < 2) || (errno) ||
152 (command < 0) || (command > 8)) {
153 printf("Usage: play device [command [param]]\n\n");
154 printf(" Valid devices:\n");
155 count_ids(TRUE);
156 printf("\n");
157 printf(" Valid commands:\n");
158 printf(" 0 [n] - play from track n [1]\n");
159 printf(" 1 - pause\n");
160 printf(" 2 - resume\n");
161 printf(" 3 - stop\n");
162 printf(" 4 - eject\n");
163 printf(" 5 n - set volume to n (0 <= n <= 255)\n");
164 printf(" 6 - current position\n");
165 printf(" 7 n s - save track n to file s\n");
166 printf(" 8 [c] - scan in direction c (f = forward, b = backward)\n\n");
167 return 0;
170 if ((id = open(argv[1], 0)) >= 0) {
171 switch (command) {
172 case 0:
173 if (!ioctl(id, B_SCSI_GET_TOC, &toc)) {
174 track.start_track = 0;
175 for (i = toc.toc_data[2]; i <= toc.toc_data[3]; i++) {
176 length = (toc.toc_data[(((i + 1) - toc.toc_data[2]) * 8) + 4 + 5] * 60) +
177 (toc.toc_data[(((i + 1) - toc.toc_data[2]) * 8) + 4 + 6]);
178 length -= ((toc.toc_data[((i - toc.toc_data[2]) * 8) + 4 + 5] * 60) +
179 (toc.toc_data[((i - toc.toc_data[2]) * 8) + 4 + 6]));
180 printf(" Track %.2d: %.2d:%.2d - ", i, length / 60, length % 60);
181 if (toc.toc_data[((i - toc.toc_data[2]) * 8) + 4 + 1] & 4)
182 printf("DATA\n");
183 else {
184 printf("AUDIO\n");
185 if (!track.start_track)
186 track.start_track = i;
189 if (track.start_track) {
190 if (argc > 3) {
191 req_track = strtol (argv[3], 0, 0);
192 if ((req_track < toc.toc_data[2]) || (req_track > toc.toc_data[3]))
193 printf("Requested track is out of range\n");
194 else
195 if (toc.toc_data[((req_track - toc.toc_data[2]) * 8) + 4 + 1] & 4)
196 printf("Requested track is not an audio track\n");
197 else {
198 track.start_track = req_track;
199 play(id, &track);
202 else
203 play(id, &track);
205 else
206 printf("No audio tracks on CD\n");
208 else
209 printf("Could not read table of contents on CD\n");
210 break;
212 case 1:
213 printf("Pausing audio\n");
214 ioctl(id, B_SCSI_PAUSE_AUDIO);
215 break;
217 case 2:
218 printf("Resuming audio\n");
219 ioctl(id, B_SCSI_RESUME_AUDIO);
220 break;
222 case 3:
223 printf("Stopping audio\n");
224 ioctl(id, B_SCSI_STOP_AUDIO);
225 break;
227 case 4:
228 printf("Ejecting CD\n");
229 ioctl(id, B_SCSI_EJECT);
230 break;
232 case 5:
233 if (argc < 4)
234 printf("Specify the volume\n");
235 else {
236 vol = strtol (argv[3], 0, 0);
237 if ((vol < 0) || (vol > 255))
238 printf("Volume is out of range (0 - 255)\n");
239 else {
240 printf("Setting volume to %ld\n", vol);
241 volume.port0_volume = vol;
242 volume.port1_volume = vol;
243 volume.flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME;
244 ioctl(id, B_SCSI_SET_VOLUME, &volume);
247 break;
249 case 6:
250 if (ioctl(id, B_SCSI_GET_POSITION, &position) == B_ERROR)
251 printf("Could not get current position\n");
252 else {
253 switch(position.position[1]) {
254 case 0x00:
255 printf("Position not supported by device\n");
256 break;
258 case 0x11:
259 printf("Playing track %d (%.2d:%.2d:%.2d)\n",
260 position.position[6],
261 position.position[9],
262 position.position[10],
263 position.position[11]);
264 break;
266 case 0x12:
267 printf("Paused at track %d (%.2d:%.2d:%.2d)\n",
268 position.position[6],
269 position.position[9],
270 position.position[10],
271 position.position[11]);
272 break;
274 case 0x13:
275 printf("Play has been completed\n");
276 break;
278 case 0x14:
279 printf("Play stopped due to error\n");
280 break;
282 case 0x15:
283 printf("No status to return\n");
284 break;
286 default:
287 printf("Unexpected result: %.2x\n",
288 position.position[1]);
291 break;
293 case 7:
294 if (argc < 4) {
295 printf("Specify the track to save\n");
296 break;
299 if (argc < 5) {
300 printf("Specify a file to save to\n");
301 break;
304 f = fopen(argv[4], "w");
305 if (f == NULL) {
306 printf("Un-able to create %s\n", argv[4]);
307 break;
310 req_track = strtol (argv[3], 0, 0);
311 if (!ioctl(id, B_SCSI_GET_TOC, &toc)) {
312 if (req_track > toc.toc_data[3]) {
313 printf("Track %ld is out of range [%d-%d]\n", req_track,
314 toc.toc_data[2], toc.toc_data[3]);
315 break;
317 index = 0;
318 while (toc.toc_data[4 + (index * 8) + 2] != req_track) {
319 index++;
321 start = (toc.toc_data[4 + (index * 8) + 5] * 60 * 75) +
322 (toc.toc_data[4 + (index * 8) + 6] * 75) +
323 toc.toc_data[4 + (index * 8) + 7];
324 index++;
325 length = ((toc.toc_data[4 + (index * 8) + 5] * 60 * 75) +
326 (toc.toc_data[4 + (index * 8) + 6] * 75) +
327 toc.toc_data[4 + (index * 8) + 7]) - start;
329 frames = min_c(1 * 75, (int) length);
330 read_cd.buffer = (char *)malloc(frames * 2352);
332 printf("Saving track %ld to %s...\n", req_track, argv[4]);
333 while (length) {
334 index = start;
335 read_cd.start_m = index / (60 * 75);
336 index %= (60 * 75);
337 read_cd.start_s = index / 75;
338 index %= 75;
339 read_cd.start_f = index;
341 index = min_c((int)frames, length);
342 read_cd.buffer_length = index * 2352;
343 length -= index;
344 start += index;
346 read_cd.length_m = index / (60 * 75);
347 index %= (60 * 75);
348 read_cd.length_s = index / 75;
349 index %= 75;
350 read_cd.length_f = index;
352 for (i = 0; i < 5; i++)
353 if (ioctl(id, B_SCSI_READ_CD, &read_cd) == B_NO_ERROR)
354 break;
355 if (i == 5) {
356 printf("Error reading CD-DA\n");
357 break;
359 buf = (uchar *)read_cd.buffer;
360 for (i = 0; i < read_cd.buffer_length; i += 2) {
361 tmp = (short)((buf[1] << 8) | buf[0]);
362 *(short *)(&buf[0]) = tmp;
363 buf += 2;
365 fwrite(read_cd.buffer, read_cd.buffer_length, 1, f);
367 free(read_cd.buffer);
368 fclose(f);
370 else
371 printf("Failed to read table of contents\n");
372 break;
374 case 8:
375 if (argc == 4) {
376 if (!strcmp(argv[3], "f") || !strcmp(argv[3], "F"))
377 scan.direction = 1;
378 else if (!strcmp(argv[3], "b") || !strcmp(argv[3], "B"))
379 scan.direction = -1;
380 else {
381 printf("Use 'f' to scan forward, 'b' to scan backwards\n");
382 break;
385 else
386 scan.direction = 0;
387 scan.speed = 0;
388 if (ioctl(id, B_SCSI_SCAN, &scan) == B_ERROR)
389 printf("Error trying to scan\n");
390 else
391 printf("Scanning...\n");
392 break;
394 close(id);
396 else
397 printf("CD player is empty or invalid scsi-id\n");
398 return 0;