xref: /aosp_15_r20/external/flac/src/libFLAC/ogg_helper.c (revision 600f14f40d737144c998e2ec7a483122d3776fbc)
1*600f14f4SXin Li /* libFLAC - Free Lossless Audio Codec
2*600f14f4SXin Li  * Copyright (C) 2004-2009  Josh Coalson
3*600f14f4SXin Li  * Copyright (C) 2011-2023  Xiph.Org Foundation
4*600f14f4SXin Li  *
5*600f14f4SXin Li  * Redistribution and use in source and binary forms, with or without
6*600f14f4SXin Li  * modification, are permitted provided that the following conditions
7*600f14f4SXin Li  * are met:
8*600f14f4SXin Li  *
9*600f14f4SXin Li  * - Redistributions of source code must retain the above copyright
10*600f14f4SXin Li  * notice, this list of conditions and the following disclaimer.
11*600f14f4SXin Li  *
12*600f14f4SXin Li  * - Redistributions in binary form must reproduce the above copyright
13*600f14f4SXin Li  * notice, this list of conditions and the following disclaimer in the
14*600f14f4SXin Li  * documentation and/or other materials provided with the distribution.
15*600f14f4SXin Li  *
16*600f14f4SXin Li  * - Neither the name of the Xiph.org Foundation nor the names of its
17*600f14f4SXin Li  * contributors may be used to endorse or promote products derived from
18*600f14f4SXin Li  * this software without specific prior written permission.
19*600f14f4SXin Li  *
20*600f14f4SXin Li  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*600f14f4SXin Li  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*600f14f4SXin Li  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*600f14f4SXin Li  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24*600f14f4SXin Li  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25*600f14f4SXin Li  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26*600f14f4SXin Li  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27*600f14f4SXin Li  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28*600f14f4SXin Li  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29*600f14f4SXin Li  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30*600f14f4SXin Li  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*600f14f4SXin Li  */
32*600f14f4SXin Li 
33*600f14f4SXin Li #ifdef HAVE_CONFIG_H
34*600f14f4SXin Li #  include <config.h>
35*600f14f4SXin Li #endif
36*600f14f4SXin Li 
37*600f14f4SXin Li #include <stdlib.h> /* for malloc() */
38*600f14f4SXin Li #include <string.h> /* for memcmp(), memcpy() */
39*600f14f4SXin Li #include "FLAC/assert.h"
40*600f14f4SXin Li #include "share/alloc.h"
41*600f14f4SXin Li #include "private/ogg_helper.h"
42*600f14f4SXin Li #include "protected/stream_encoder.h"
43*600f14f4SXin Li 
44*600f14f4SXin Li 
full_read_(FLAC__StreamEncoder * encoder,FLAC__byte * buffer,size_t bytes,FLAC__StreamEncoderReadCallback read_callback,void * client_data)45*600f14f4SXin Li static FLAC__bool full_read_(FLAC__StreamEncoder *encoder, FLAC__byte *buffer, size_t bytes, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
46*600f14f4SXin Li {
47*600f14f4SXin Li 	while(bytes > 0) {
48*600f14f4SXin Li 		size_t bytes_read = bytes;
49*600f14f4SXin Li 		switch(read_callback(encoder, buffer, &bytes_read, client_data)) {
50*600f14f4SXin Li 			case FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE:
51*600f14f4SXin Li 				bytes -= bytes_read;
52*600f14f4SXin Li 				buffer += bytes_read;
53*600f14f4SXin Li 				break;
54*600f14f4SXin Li 			case FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM:
55*600f14f4SXin Li 				if(bytes_read == 0) {
56*600f14f4SXin Li 					encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
57*600f14f4SXin Li 					return false;
58*600f14f4SXin Li 				}
59*600f14f4SXin Li 				bytes -= bytes_read;
60*600f14f4SXin Li 				buffer += bytes_read;
61*600f14f4SXin Li 				break;
62*600f14f4SXin Li 			case FLAC__STREAM_ENCODER_READ_STATUS_ABORT:
63*600f14f4SXin Li 				encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
64*600f14f4SXin Li 				return false;
65*600f14f4SXin Li 			case FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED:
66*600f14f4SXin Li 				return false;
67*600f14f4SXin Li 			default:
68*600f14f4SXin Li 				/* double protection: */
69*600f14f4SXin Li 				FLAC__ASSERT(0);
70*600f14f4SXin Li 				encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
71*600f14f4SXin Li 				return false;
72*600f14f4SXin Li 		}
73*600f14f4SXin Li 	}
74*600f14f4SXin Li 
75*600f14f4SXin Li 	return true;
76*600f14f4SXin Li }
77*600f14f4SXin Li 
simple_ogg_page__init(ogg_page * page)78*600f14f4SXin Li void simple_ogg_page__init(ogg_page *page)
79*600f14f4SXin Li {
80*600f14f4SXin Li 	page->header = 0;
81*600f14f4SXin Li 	page->header_len = 0;
82*600f14f4SXin Li 	page->body = 0;
83*600f14f4SXin Li 	page->body_len = 0;
84*600f14f4SXin Li }
85*600f14f4SXin Li 
simple_ogg_page__clear(ogg_page * page)86*600f14f4SXin Li void simple_ogg_page__clear(ogg_page *page)
87*600f14f4SXin Li {
88*600f14f4SXin Li 	if(page->header)
89*600f14f4SXin Li 		free(page->header);
90*600f14f4SXin Li 	if(page->body)
91*600f14f4SXin Li 		free(page->body);
92*600f14f4SXin Li 	simple_ogg_page__init(page);
93*600f14f4SXin Li }
94*600f14f4SXin Li 
simple_ogg_page__get_at(FLAC__StreamEncoder * encoder,FLAC__uint64 position,ogg_page * page,FLAC__StreamEncoderSeekCallback seek_callback,FLAC__StreamEncoderReadCallback read_callback,void * client_data)95*600f14f4SXin Li FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
96*600f14f4SXin Li {
97*600f14f4SXin Li 	static const uint32_t OGG_HEADER_FIXED_PORTION_LEN = 27;
98*600f14f4SXin Li 	static const uint32_t OGG_MAX_HEADER_LEN = 27/*OGG_HEADER_FIXED_PORTION_LEN*/ + 255;
99*600f14f4SXin Li 	FLAC__byte crc[4];
100*600f14f4SXin Li 	FLAC__StreamEncoderSeekStatus seek_status;
101*600f14f4SXin Li 
102*600f14f4SXin Li 	FLAC__ASSERT(page->header == 0);
103*600f14f4SXin Li 	FLAC__ASSERT(page->header_len == 0);
104*600f14f4SXin Li 	FLAC__ASSERT(page->body == 0);
105*600f14f4SXin Li 	FLAC__ASSERT(page->body_len == 0);
106*600f14f4SXin Li 
107*600f14f4SXin Li 	/* move the stream pointer to the supposed beginning of the page */
108*600f14f4SXin Li 	if(0 == seek_callback)
109*600f14f4SXin Li 		return false;
110*600f14f4SXin Li 	if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
111*600f14f4SXin Li 		if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
112*600f14f4SXin Li 			encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
113*600f14f4SXin Li 		return false;
114*600f14f4SXin Li 	}
115*600f14f4SXin Li 
116*600f14f4SXin Li 	/* allocate space for the page header */
117*600f14f4SXin Li 	if(0 == (page->header = safe_malloc_(OGG_MAX_HEADER_LEN))) {
118*600f14f4SXin Li 		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
119*600f14f4SXin Li 		return false;
120*600f14f4SXin Li 	}
121*600f14f4SXin Li 
122*600f14f4SXin Li 	/* read in the fixed part of the page header (up to but not including
123*600f14f4SXin Li 	 * the segment table */
124*600f14f4SXin Li 	if(!full_read_(encoder, page->header, OGG_HEADER_FIXED_PORTION_LEN, read_callback, client_data))
125*600f14f4SXin Li 		return false;
126*600f14f4SXin Li 
127*600f14f4SXin Li 	page->header_len = OGG_HEADER_FIXED_PORTION_LEN + page->header[26];
128*600f14f4SXin Li 
129*600f14f4SXin Li 	/* check to see if it's a correct, "simple" page (one packet only) */
130*600f14f4SXin Li 	if(
131*600f14f4SXin Li 		memcmp(page->header, "OggS", 4) ||               /* doesn't start with OggS */
132*600f14f4SXin Li 		(page->header[5] & 0x01) ||                      /* continued packet */
133*600f14f4SXin Li 		memcmp(page->header+6, "\0\0\0\0\0\0\0\0", 8) || /* granulepos is non-zero */
134*600f14f4SXin Li 		page->header[26] == 0                            /* packet is 0-size */
135*600f14f4SXin Li 	) {
136*600f14f4SXin Li 		encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
137*600f14f4SXin Li 		return false;
138*600f14f4SXin Li 	}
139*600f14f4SXin Li 
140*600f14f4SXin Li 	/* read in the segment table */
141*600f14f4SXin Li 	if(!full_read_(encoder, page->header + OGG_HEADER_FIXED_PORTION_LEN, page->header[26], read_callback, client_data))
142*600f14f4SXin Li 		return false;
143*600f14f4SXin Li 
144*600f14f4SXin Li 	{
145*600f14f4SXin Li 		uint32_t i;
146*600f14f4SXin Li 
147*600f14f4SXin Li 		/* check to see that it specifies a single packet */
148*600f14f4SXin Li 		for(i = 0; i < (uint32_t)page->header[26] - 1; i++) {
149*600f14f4SXin Li 			if(page->header[i + OGG_HEADER_FIXED_PORTION_LEN] != 255) {
150*600f14f4SXin Li 				encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
151*600f14f4SXin Li 				return false;
152*600f14f4SXin Li 			}
153*600f14f4SXin Li 		}
154*600f14f4SXin Li 
155*600f14f4SXin Li 		page->body_len = 255 * i + page->header[i + OGG_HEADER_FIXED_PORTION_LEN];
156*600f14f4SXin Li 	}
157*600f14f4SXin Li 
158*600f14f4SXin Li 	/* allocate space for the page body */
159*600f14f4SXin Li 	if(0 == (page->body = safe_malloc_(page->body_len))) {
160*600f14f4SXin Li 		encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
161*600f14f4SXin Li 		return false;
162*600f14f4SXin Li 	}
163*600f14f4SXin Li 
164*600f14f4SXin Li 	/* read in the page body */
165*600f14f4SXin Li 	if(!full_read_(encoder, page->body, page->body_len, read_callback, client_data))
166*600f14f4SXin Li 		return false;
167*600f14f4SXin Li 
168*600f14f4SXin Li 	/* check the CRC */
169*600f14f4SXin Li 	memcpy(crc, page->header+22, 4);
170*600f14f4SXin Li 	ogg_page_checksum_set(page);
171*600f14f4SXin Li 	if(memcmp(crc, page->header+22, 4)) {
172*600f14f4SXin Li 		encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
173*600f14f4SXin Li 		return false;
174*600f14f4SXin Li 	}
175*600f14f4SXin Li 
176*600f14f4SXin Li 	return true;
177*600f14f4SXin Li }
178*600f14f4SXin Li 
simple_ogg_page__set_at(FLAC__StreamEncoder * encoder,FLAC__uint64 position,ogg_page * page,FLAC__StreamEncoderSeekCallback seek_callback,FLAC__StreamEncoderWriteCallback write_callback,void * client_data)179*600f14f4SXin Li FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data)
180*600f14f4SXin Li {
181*600f14f4SXin Li 	FLAC__StreamEncoderSeekStatus seek_status;
182*600f14f4SXin Li 
183*600f14f4SXin Li 	FLAC__ASSERT(page->header != 0);
184*600f14f4SXin Li 	FLAC__ASSERT(page->header_len != 0);
185*600f14f4SXin Li 	FLAC__ASSERT(page->body != 0);
186*600f14f4SXin Li 	FLAC__ASSERT(page->body_len != 0);
187*600f14f4SXin Li 
188*600f14f4SXin Li 	/* move the stream pointer to the supposed beginning of the page */
189*600f14f4SXin Li 	if(0 == seek_callback)
190*600f14f4SXin Li 		return false;
191*600f14f4SXin Li 	if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
192*600f14f4SXin Li 		if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
193*600f14f4SXin Li 			encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
194*600f14f4SXin Li 		return false;
195*600f14f4SXin Li 	}
196*600f14f4SXin Li 
197*600f14f4SXin Li 	ogg_page_checksum_set(page);
198*600f14f4SXin Li 
199*600f14f4SXin Li 	/* re-write the page */
200*600f14f4SXin Li 	if(write_callback((FLAC__StreamEncoder*)encoder, page->header, page->header_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
201*600f14f4SXin Li 		encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
202*600f14f4SXin Li 		return false;
203*600f14f4SXin Li 	}
204*600f14f4SXin Li 	if(write_callback((FLAC__StreamEncoder*)encoder, page->body, page->body_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
205*600f14f4SXin Li 		encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
206*600f14f4SXin Li 		return false;
207*600f14f4SXin Li 	}
208*600f14f4SXin Li 
209*600f14f4SXin Li 	return true;
210*600f14f4SXin Li }
211