Coverage Report

Created: 2025-12-14 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libsndfile/src/pvf.c
Line
Count
Source
1
/*
2
** Copyright (C) 2002-2016 Erik de Castro Lopo <erikd@mega-nerd.com>
3
**
4
** This program is free software; you can redistribute it and/or modify
5
** it under the terms of the GNU Lesser General Public License as published by
6
** the Free Software Foundation; either version 2.1 of the License, or
7
** (at your option) any later version.
8
**
9
** This program is distributed in the hope that it will be useful,
10
** but WITHOUT ANY WARRANTY; without even the implied warranty of
11
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
** GNU Lesser General Public License for more details.
13
**
14
** You should have received a copy of the GNU Lesser General Public License
15
** along with this program; if not, write to the Free Software
16
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
*/
18
19
#include  "sfconfig.h"
20
21
#include  <stdio.h>
22
#include  <fcntl.h>
23
#include  <string.h>
24
#include  <ctype.h>
25
26
#include  "sndfile.h"
27
#include  "sfendian.h"
28
#include  "common.h"
29
30
/*------------------------------------------------------------------------------
31
** Macros to handle big/little endian issues.
32
*/
33
34
271
#define PVF1_MARKER   (MAKE_MARKER ('P', 'V', 'F', '1'))
35
36
/*------------------------------------------------------------------------------
37
** Private static functions.
38
*/
39
40
static  int   pvf_close   (SF_PRIVATE *psf) ;
41
42
static int    pvf_write_header (SF_PRIVATE *psf, int calc_length) ;
43
static int    pvf_read_header (SF_PRIVATE *psf) ;
44
45
/*------------------------------------------------------------------------------
46
** Public function.
47
*/
48
49
int
50
pvf_open  (SF_PRIVATE *psf)
51
271
{ int   subformat ;
52
271
  int   error = 0 ;
53
54
271
  if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0))
55
271
  { if ((error = pvf_read_header (psf)))
56
16
      return error ;
57
271
    } ;
58
59
255
  subformat = SF_CODEC (psf->sf.format) ;
60
61
255
  if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
62
0
  { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_PVF)
63
0
      return  SFE_BAD_OPEN_FORMAT ;
64
65
0
    psf->endian = SF_ENDIAN_BIG ;
66
67
0
    if (pvf_write_header (psf, SF_FALSE))
68
0
      return psf->error ;
69
70
0
    psf->write_header = pvf_write_header ;
71
255
    } ;
72
73
255
  psf->container_close = pvf_close ;
74
75
255
  psf->blockwidth = psf->bytewidth * psf->sf.channels ;
76
77
255
  switch (subformat)
78
255
  { case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */
79
205
    case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */
80
255
    case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */
81
255
        error = pcm_init (psf) ;
82
255
        break ;
83
84
0
    default : break ;
85
255
    } ;
86
87
255
  return error ;
88
255
} /* pvf_open */
89
90
/*------------------------------------------------------------------------------
91
*/
92
93
static int
94
pvf_close (SF_PRIVATE * UNUSED (psf))
95
255
{
96
255
  return 0 ;
97
255
} /* pvf_close */
98
99
static int
100
pvf_write_header (SF_PRIVATE *psf, int UNUSED (calc_length))
101
0
{ sf_count_t  current ;
102
103
0
  if (psf->pipeoffset > 0)
104
0
    return 0 ;
105
106
0
  current = psf_ftell (psf) ;
107
108
  /* Reset the current header length to zero. */
109
0
  psf->header.ptr [0] = 0 ;
110
0
  psf->header.indx = 0 ;
111
112
0
  if (psf->is_pipe == SF_FALSE)
113
0
    psf_fseek (psf, 0, SEEK_SET) ;
114
115
0
  snprintf ((char*) psf->header.ptr, psf->header.len, "PVF1\n%d %d %d\n",
116
0
    psf->sf.channels, psf->sf.samplerate, psf->bytewidth * 8) ;
117
118
0
  psf->header.indx = strlen ((char*) psf->header.ptr) ;
119
120
  /* Header construction complete so write it out. */
121
0
  psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ;
122
123
0
  if (psf->error)
124
0
    return psf->error ;
125
126
0
  psf->dataoffset = psf->header.indx ;
127
128
0
  if (current > 0)
129
0
    psf_fseek (psf, current, SEEK_SET) ;
130
131
0
  return psf->error ;
132
0
} /* pvf_write_header */
133
134
static int
135
pvf_read_header (SF_PRIVATE *psf)
136
271
{ char  buffer [32] ;
137
271
  int   marker, channels, samplerate, bitwidth ;
138
139
271
  psf_binheader_readf (psf, "pmj", 0, &marker, 1) ;
140
271
  psf_log_printf (psf, "%M\n", marker) ;
141
142
271
  if (marker != PVF1_MARKER)
143
0
    return SFE_PVF_NO_PVF1 ;
144
145
  /* Grab characters up until a newline which is replaced by an EOS. */
146
271
  psf_binheader_readf (psf, "G", buffer, sizeof (buffer)) ;
147
148
271
  if (sscanf (buffer, "%d %d %d", &channels, &samplerate, &bitwidth) != 3)
149
15
    return SFE_PVF_BAD_HEADER ;
150
151
256
  psf_log_printf (psf, " Channels    : %d\n Sample rate : %d\n Bit width   : %d\n",
152
256
        channels, samplerate, bitwidth) ;
153
154
256
  psf->sf.channels = channels ;
155
256
  psf->sf.samplerate = samplerate ;
156
157
256
  switch (bitwidth)
158
256
  { case 8 :
159
170
        psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_S8 ;
160
170
        psf->bytewidth = 1 ;
161
170
        break ;
162
163
35
    case 16 :
164
35
        psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_16 ;
165
35
        psf->bytewidth = 2 ;
166
35
        break ;
167
50
    case 32 :
168
50
        psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_32 ;
169
50
        psf->bytewidth = 4 ;
170
50
        break ;
171
172
1
    default :
173
1
        return SFE_PVF_BAD_BITWIDTH ;
174
256
    } ;
175
176
255
  psf->dataoffset = psf_ftell (psf) ;
177
255
  psf_log_printf (psf, " Data Offset : %D\n", psf->dataoffset) ;
178
179
255
  psf->endian = SF_ENDIAN_BIG ;
180
181
255
  psf->datalength = psf->filelength - psf->dataoffset ;
182
255
  psf->blockwidth = psf->sf.channels * psf->bytewidth ;
183
184
255
  if (! psf->sf.frames && psf->blockwidth)
185
254
    psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
186
187
255
  return 0 ;
188
256
} /* pvf_read_header */