root/usr/src/cmd/audio/audioconvert/file.cc
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 1993-2003 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/param.h>

#include <Audio.h>
#include <AudioFile.h>
#include <AudioPipe.h>
#include <AudioRawPipe.h>
#include <AudioLib.h>
#include <AudioHdr.h>

#include <libaudio.h>
#include <audio/au.h>

extern char *Stdin;
extern char *Stdout;

#include <convert.h>

// append contents of buffer to output audio stream.

AudioError
write_output(AudioBuffer* buf, AudioStream* ofp)
{
        unsigned char   *cp;
        size_t          len;
        Double          pos;
        AudioError      err;

        pos = ofp->GetLength();
        len = (size_t)buf->GetHeader().Time_to_Bytes(buf->GetLength());
        cp = (unsigned char *)buf->GetAddress();
        err = ofp->WriteData(cp, len, pos);
        return (err);
}

// open input file and return ptr to AudioUnixFile object
// path is the path to the file (or set to Stdin if standard input).
// ihdr is the input header (only used for openning raw files)
// israw flags if it's a raw file. if fflag is set, ignore an
// any existing header on raw files. offset indicates where to
// start reading the file (raw files only ??).
AudioUnixfile *open_input_file(const char *path, const AudioHdr ihdr,
                                    int israw, int fflag, off_t offset,
                                    format_type& fmt)
{
        AudioUnixfile*  ifp;
        int             fd;
        int             file_type; // ignore this ...
        int             infosize; // ignore this ...
        au_filehdr_t    fhdr;
        Audio_hdr       ohdr;   // ignore this ...
        unsigned int    hsize;

        // need to let caller know what format this is. so far, only raw
        // and sun are supported....
        fmt = (israw ? F_RAW : F_SUN);

        // no file
        if (!path) {
                // no file? shouldn't happen. bomb out.
                Err(MGET("no input file specified\n"));
                exit(1);
        }

        // deal with stdin
        if (path == Stdin) {
                if (isatty(fileno(stdin))) {
                        Err(MGET(
                            "Stdin is a tty, please specify an input file\n"));
                        exit(1);
                }
                if (israw) {
                        // XXX - need to check if stdin has a file
                        // header and ignore it if fflag not set.
                        ifp = new AudioRawPipe(fileno(stdin),
                                            (FileAccess)ReadOnly, ihdr, path,
                                            offset);
                } else {
                        ifp = new AudioPipe(fileno(stdin), (FileAccess)ReadOnly,
                                            path);
                }

                if (!ifp) {
                        Err(MGET("can't open pipe to %s, skipping...\n"),
                            Stdin);
                }
                return (ifp);
        }

        // fall through for real files ...
        if (israw) {
                if ((fd = open(path, O_RDONLY)) < 0) {
                        Err(MGET("can't open %s, skipping...\n"), path);
                        perror(MGET("open"));
                        return (NULL);
                }
                if (!fflag) {
                        // check if file already has a hdr.
                        if (hsize = read(fd, (char *)&fhdr, sizeof (fhdr))
                            < 0) {
                                perror("read");
                                exit(1);
                        }
                        if (lseek(fd, 0, 0) < 0) {  // reset
                                perror("lseek");
                                exit(1);
                        }
                        if (hsize != sizeof (fhdr)) {
                                // no hdr - file too small,
                                // assume data is ok (tho it
                                // probably won't be) ...
                                ifp = new AudioRawPipe(fd, (FileAccess)ReadOnly,
                                                            ihdr, path, offset);
                        } else {
                                // Check the validity of the
                                // header and get the size of
                                // the info field
                                if (audio_decode_filehdr(fd,
                                    (unsigned char *)&fhdr, &file_type, &ohdr,
                                    &infosize) == AUDIO_SUCCESS) {
                                        close(fd); // create AudioFile()
                                        // issue a warning
                                        Err(
                                MGET("%s has a file header, ignoring -i ...\n"),
                                            path);
                                        fmt = F_SUN; // was raw ...
                                        ifp = new AudioFile(path,
                                                    (FileAccess)ReadOnly);
                                } else {
                                        // no hdr, create AudioRawPipe.
                                        ifp = new AudioRawPipe(fd,
                                                    (FileAccess)ReadOnly, ihdr,
                                                    path, offset);
                                }
                        }

                } else {        // force flag - don't even look for header
                        ifp = new AudioRawPipe(fd, (FileAccess)ReadOnly, ihdr,
                                                    path, offset);
                }
        } else {
                ifp = new AudioFile(path, (FileAccess)ReadOnly);
        }

        if (!ifp) {
                Err(MGET("can't open %s, skipping...\n"), path);
        }
        return (ifp);
}

// given a path, find the file it really points to (if it's a
// sym-link). return it's stat buf and real path.
void
get_realfile(char *&path, struct stat *st)
{
        static char     tmpf[MAXPATHLEN]; // for reading sym-link
        int             err;    // for stat err

        // first see if it's a sym-link and find real file
        err = 0;
        while (err == 0) {
                if (err = lstat(path, st) < 0) {
                        perror("lstat");
                        exit(1);
                }
                if (!err && S_ISLNK(st->st_mode)) {
                        err = readlink(path, tmpf,
                                        (sizeof (tmpf) - 1));
                        if (err > 0) {
                                tmpf[err] = '\0';
                                path = tmpf;
                                err = 0;
                        }
                } else {
                        break;
                }
        }

}

// create output audio file. if no path is supplied, use stdout.
// returns a ptr to an AudioUnixFile object.

AudioUnixfile*
create_output_file(
        const char *path,
        const AudioHdr ohdr,
        format_type ofmt,
        const char *infoString)
{
        AudioUnixfile*  ofp = 0;
        AudioError      err;    // for error msgs
        int             fd;

        if (!path) {
                if (isatty(fileno(stdout))) {
                        Err(
                    MGET("Stdout is a tty, please specify an output file\n"));
                        exit(1);
                }

                path = Stdout;
                if (ofmt == F_RAW) {
                        if (!(ofp = new AudioRawPipe(fileno(stdout),
                                                    (FileAccess)WriteOnly, ohdr,
                                                    path))) {
                                Err(
                            MGET("can't create audio raw stdout pipe\n"));
                                exit(1);
                        }
                } else if (ofmt == F_SUN) {
                        if (!(ofp = new AudioPipe(fileno(stdout),
                                            (FileAccess)WriteOnly, path))) {
                                Err(
                            MGET("can't create audio pipe for stdout\n"));
                                exit(1);
                        }
                } else {
                        // XXX - should never happen ...
                        Err(MGET("can't create output file, unknown format\n"));
                        exit(1);
                }
        } else {
                if (ofmt == F_RAW) {
                        // first open file, then attach pipe to it
                        if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC,
                                    0666)) < 0) {
                                perror(MGET("open"));
                                Err(MGET("can't create output file %s\n"),
                                    path);
                                exit(1);
                        }
                        if (!(ofp = new AudioRawPipe(fd, (FileAccess)WriteOnly,
                                                    ohdr, path))) {
                                Err(MGET("can't create raw audio pipe %s\n"),
                                    path);
                                exit(1);
                        }
                } else if (ofmt == F_SUN) {
                        if (!(ofp = new AudioFile(path,
                                                    (FileAccess)ReadWrite))) {
                                Err(MGET("can't create output file %s\n"),
                                    path);
                                exit(1);
                        }
                } else {
                        // XXX - should never happen ...
                        Err(MGET("can't create output file, unknown format\n"));
                        exit(1);
                }
        }

        // set the info string.
        ofp->SetInfostring(infoString, -1);

        // set the header and create the output audio object
        if ((err = ofp->SetHeader(ohdr)) != AUDIO_SUCCESS) {
                Err(MGET("can't set hdr on output file: %s\n"), err.msg());
                exit(1);
        }
        if ((err = ofp->Create()) != AUDIO_SUCCESS) {
                Err(MGET("can't create output file: %s\n"), err.msg());
                exit(1);
        }

        return (ofp);
}