| /* |
| * Routines for managing file input/output for AIF objects. |
| * |
| * Copyright (c) 1996-2002 by Guardsoft Pty Ltd. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif /* HAVE_CONFIG_H */ |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <string.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| |
| #ifdef WIN32 |
| #include <io.h> |
| #else /* WIN32 */ |
| #include <unistd.h> |
| #endif /* WIN32 */ |
| |
| #include "aif.h" |
| #include "aifint.h" |
| #include "aiferr.h" |
| |
| #define AIFFILE_MAGIC "AIF1.0" |
| |
| #define AIFFILE_DATA 'D' |
| #define AIFFILE_EOF 'E' |
| |
| struct aifhdr |
| { |
| char hdr_magic[6]; |
| char hdr_flag; |
| char hdr_namelen[6]; |
| char hdr_fdslen[6]; |
| char hdr_datalen[11]; |
| }; |
| typedef struct aifhdr aifhdr; |
| |
| extern int errno; |
| |
| int write_data(FILE *, char *, int); |
| |
| int |
| ToNum(char *str, int len) |
| { |
| int i; |
| int val = 0; |
| |
| for ( i = 0 ; i < len ; i++ ) |
| val = val * 10 + str[i] - '0'; |
| |
| return val; |
| } |
| |
| int |
| aif_write_set(AIFFILE *af, char *name, char *fds, char *data, int len) |
| { |
| int nlen; |
| int flen; |
| aifhdr hdr; |
| char buf[BUFSIZ]; |
| char nbuf[BUFSIZ]; |
| |
| memcpy(hdr.hdr_magic, AIFFILE_MAGIC, sizeof(hdr.hdr_magic)); |
| |
| if ( fds == NULL ) |
| { |
| hdr.hdr_flag = AIFFILE_EOF; |
| nlen = 0; |
| flen = 0; |
| len = 0; |
| } |
| else |
| { |
| hdr.hdr_flag = AIFFILE_DATA; |
| |
| if ( name == NULL ) |
| snprintf(nbuf, BUFSIZ, "_ar_%d", af->af_cnt++); |
| else |
| strcpy(nbuf, name); |
| |
| nlen = strlen(nbuf) + 1; |
| flen = strlen(fds) + 1; |
| } |
| |
| snprintf(buf, BUFSIZ, "%06d", nlen); |
| memcpy(hdr.hdr_namelen, buf, sizeof(hdr.hdr_namelen)); |
| |
| snprintf(buf, BUFSIZ, "%06d", flen); |
| memcpy(hdr.hdr_fdslen, buf, sizeof(hdr.hdr_fdslen)); |
| |
| snprintf(buf, BUFSIZ, "%011d", len); |
| memcpy(hdr.hdr_datalen, buf, sizeof(hdr.hdr_datalen)); |
| |
| if ( write_data(af->af_fp, (char *)&hdr, sizeof(aifhdr)) < 0 ) |
| return -1; |
| |
| if ( fds == NULL ) |
| return 0; |
| |
| if |
| ( |
| write_data(af->af_fp, nbuf, nlen) < 0 |
| || |
| write_data(af->af_fp, fds, flen) < 0 |
| || |
| write_data(af->af_fp, data, len) < 0 |
| ) |
| return -1; |
| |
| return 0; |
| } |
| |
| int |
| write_data(FILE *fp, char *buf, int len) |
| { |
| int n; |
| |
| while ( (n = fwrite(buf, 1, len, fp)) < len ) |
| { |
| if ( n < 0 ) |
| { |
| SetAIFError(AIFERR_WRITE, strerror(errno)); |
| return -1; |
| } |
| |
| len -= n; |
| buf += n; |
| } |
| |
| return 0; |
| } |
| |
| int |
| AIFWriteSet(AIFFILE *af, AIF *a, char *name) |
| { |
| if ( a == (AIF *)NULL || af == (AIFFILE *)NULL ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return -1; |
| } |
| |
| if |
| ( |
| af->af_mode != AIFMODE_CREATE |
| && |
| af->af_mode != AIFMODE_APPEND |
| ) |
| { |
| SetAIFError(AIFERR_MODE, NULL); |
| return -1; |
| } |
| |
| return aif_write_set(af, name, AIF_FORMAT(a), AIF_DATA(a), AIF_LEN(a)); |
| } |
| |
| int |
| aif_read_set(AIFFILE *af, AIF **a, char **name) |
| { |
| int l; |
| int flen; |
| int nlen; |
| int dlen; |
| aifhdr hdr; |
| char * fds; |
| char * data; |
| static AIF * _aif_read_aif = (AIF *)NULL; |
| static char * _aif_read_name = NULL; |
| |
| if ( (l = fread((char *)&hdr, sizeof(aifhdr), 1, af->af_fp)) < 0 ) |
| { |
| SetAIFError(AIFERR_READ, strerror(errno)); |
| return -1; |
| } |
| |
| if |
| ( |
| l < 1 |
| || |
| strncmp(hdr.hdr_magic, AIFFILE_MAGIC, sizeof(hdr.hdr_magic)) != 0 ) |
| { |
| SetAIFError(AIFERR_BADHDR, NULL); |
| return -1; |
| } |
| |
| if ( hdr.hdr_flag == AIFFILE_EOF ) |
| return 0; |
| |
| nlen = ToNum(hdr.hdr_namelen, sizeof(hdr.hdr_namelen)); |
| flen = ToNum(hdr.hdr_fdslen, sizeof(hdr.hdr_fdslen)); |
| dlen = ToNum(hdr.hdr_datalen, sizeof(hdr.hdr_datalen)); |
| |
| if ( a == (AIF **)NULL ) |
| { |
| /* |
| ** Skip over data. |
| */ |
| if ( fseek(af->af_fp, nlen + flen + dlen, SEEK_CUR) < 0 ) |
| { |
| SetAIFError(AIFERR_SEEK, strerror(errno)); |
| return -1; |
| } |
| |
| return 1; |
| } |
| |
| if ( _aif_read_name != NULL ) |
| _aif_free(_aif_read_name); |
| |
| _aif_read_name = (char *)_aif_alloc(nlen); |
| |
| fds = (char *)_aif_alloc(flen); |
| data = (char *)_aif_alloc(dlen); |
| |
| if ( (l = fread(_aif_read_name, 1, nlen, af->af_fp)) < 0 || l < nlen ) |
| { |
| SetAIFError(AIFERR_READ, strerror(errno)); |
| return -1; |
| } |
| |
| if ( (l = fread(fds, 1, flen, af->af_fp)) < 0 || l < flen ) |
| { |
| SetAIFError(AIFERR_READ, strerror(errno)); |
| return -1; |
| } |
| |
| if ( (l = fread(data, 1, dlen, af->af_fp)) < 0 || l < dlen ) |
| { |
| SetAIFError(AIFERR_READ, strerror(errno)); |
| return -1; |
| } |
| |
| if ( _aif_read_aif != (AIF *)NULL ) |
| AIFFree(_aif_read_aif); |
| |
| *a = _aif_read_aif = MakeAIF(fds, data); |
| |
| if ( name != (char **)NULL ) |
| *name = _aif_read_name; |
| |
| return 1; |
| } |
| |
| AIF * |
| AIFReadSet(AIFFILE *af, char **name) |
| { |
| AIF * a; |
| |
| if ( af == (AIFFILE *)NULL ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return (AIF *)NULL; |
| } |
| |
| if ( af->af_mode != AIFMODE_READ ) |
| { |
| SetAIFError(AIFERR_MODE, NULL); |
| return (AIF *)NULL; |
| } |
| |
| if ( aif_read_set(af, &a, name) <= 0 ) |
| return (AIF *)NULL; |
| |
| return a; |
| } |
| |
| AIFFILE * |
| AIFOpenSet(char *file, int mode) |
| { |
| int n; |
| int cnt = 0; |
| int fd; |
| int created = 0; |
| char * fmode; |
| FILE * fp; |
| AIFFILE * af; |
| |
| switch ( mode ) |
| { |
| case AIFMODE_READ: |
| fmode = "r"; |
| break; |
| |
| case AIFMODE_CREATE: |
| fmode = "w"; |
| break; |
| |
| case AIFMODE_APPEND: |
| fmode = "r+"; |
| |
| if ( access(file, R_OK) < 0 ) |
| { |
| if ( (fd = creat(file, 0644)) < 0 ) |
| { |
| SetAIFError(AIFERR_OPEN, strerror(errno)); |
| return (AIFFILE *)NULL; |
| } |
| |
| (void)close(fd); |
| created = 1; |
| } |
| |
| break; |
| |
| default: |
| /* should never happen */ |
| fmode = ""; |
| assert(0); |
| } |
| |
| if ( (fp = fopen(file, fmode)) == (FILE *)NULL ) |
| { |
| SetAIFError(AIFERR_OPEN, strerror(errno)); |
| return (AIFFILE *)NULL; |
| } |
| |
| af = (AIFFILE *)_aif_alloc(sizeof(AIFFILE)); |
| af->af_fp = fp; |
| af->af_mode = mode; |
| |
| if ( mode == AIFMODE_APPEND ) |
| { |
| /* |
| ** Count entries. |
| */ |
| while ( (n = aif_read_set(af, (AIF **)NULL, (char **)NULL)) > 0 ) |
| cnt++; |
| |
| if ( n < 0 && !created ) |
| { |
| fclose(af->af_fp); |
| _aif_free(af); |
| return (AIFFILE *)NULL; |
| } |
| |
| /* |
| ** Back up over EOF header. |
| */ |
| if |
| ( |
| cnt > 0 |
| && |
| fseek(af->af_fp, -((int)sizeof(aifhdr)), SEEK_CUR) < 0 |
| ) |
| { |
| SetAIFError(AIFERR_SEEK, strerror(errno)); |
| fclose(af->af_fp); |
| _aif_free(af); |
| return (AIFFILE *)NULL; |
| } |
| } |
| |
| af->af_cnt = cnt; |
| |
| return af; |
| } |
| |
| int |
| AIFCloseSet(AIFFILE *af) |
| { |
| if ( af == (AIFFILE *)NULL ) |
| { |
| SetAIFError(AIFERR_BADARG, NULL); |
| return -1; |
| } |
| |
| if |
| ( |
| ( |
| af->af_mode == AIFMODE_CREATE |
| || |
| af->af_mode == AIFMODE_APPEND |
| ) |
| && |
| aif_write_set(af, NULL, NULL, NULL, 0) < 0 |
| ) |
| return -1; |
| |
| fclose(af->af_fp); |
| _aif_free(af); |
| |
| return 0; |
| } |