more doxygen comments
[flac.git] / include / OggFLAC / stream_decoder.h
1 /* libOggFLAC - Free Lossless Audio Codec + Ogg library
2  * Copyright (C) 2002  Josh Coalson
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA  02111-1307, USA.
18  */
19
20 #ifndef OggFLAC__STREAM_DECODER_H
21 #define OggFLAC__STREAM_DECODER_H
22
23 #include "FLAC/stream_decoder.h"
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29
30 /** \file include/OggFLAC/stream_decoder.h
31  *
32  *  \brief
33  *  This module contains the functions which implement the stream
34  *  decoder.
35  *
36  *  See the detailed documentation in the
37  *  \link oggflac_stream_decoder stream decoder \endlink module.
38  */
39
40 /** \defgroup oggflac_decoder OggFLAC/ *_decoder.h: decoder interfaces
41  *  \ingroup oggflac
42  *
43  *  \brief
44  *  This module describes the decoder layers provided by libOggFLAC.
45  *
46  * libOggFLAC currently provides the same stream layer access as libFLAC;
47  * the interface is identical.  See the \link flac_decoder FLAC
48  * decoder module \endlink for full documentation.
49  */
50
51 /** \defgroup oggflac_stream_decoder OggFLAC/stream_decoder.h: stream decoder interface
52  *  \ingroup oggflac_decoder
53  *
54  *  \brief
55  *  This module contains the functions which implement the stream
56  *  decoder.
57  *
58  * The interface here is identical to FLAC's stream decoder,
59  * including the callbacks.  See the \link flac_stream_decoder
60  * FLAC stream decoder module \endlink for full documentation.
61  *
62  * \{
63  */
64
65
66 /** State values for an OggFLAC__StreamDecoder
67  *
68  *  The decoder's state can be obtained by calling OggFLAC__stream_decoder_get_state().
69  */
70 typedef enum {
71
72         OggFLAC__STREAM_DECODER_OK = 0,
73         /**< The decoder is in the normal OK state. */
74
75         OggFLAC__STREAM_DECODER_OGG_ERROR,
76         /**< An error occurred in the underlying Ogg layer.  */
77
78         OggFLAC__STREAM_DECODER_READ_ERROR,
79         /**< The read callback returned an error. */
80
81         OggFLAC__STREAM_DECODER_FLAC_STREAM_DECODER_ERROR,
82         /**< An error occurred in the underlying FLAC stream decoder;
83          * check OggFLAC__stream_decoder_get_FLAC_stream_decoder_state().
84          */
85
86         OggFLAC__STREAM_DECODER_INVALID_CALLBACK,
87         /**< The decoder was initialized before setting all the required callbacks. */
88
89         OggFLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
90         /**< Memory allocation failed. */
91
92         OggFLAC__STREAM_DECODER_ALREADY_INITIALIZED,
93         /**< OggFLAC__stream_decoder_init() was called when the decoder was
94          * already initialized, usually because
95          * OggFLAC__stream_decoder_finish() was not called.
96          */
97
98         OggFLAC__STREAM_DECODER_UNINITIALIZED
99         /**< The decoder is in the uninitialized state. */
100
101 } OggFLAC__StreamDecoderState;
102
103 /** Maps an OggFLAC__StreamDecoderState to a C string.
104  *
105  *  Using an OggFLAC__StreamDecoderState as the index to this array
106  *  will give the string equivalent.  The contents should not be modified.
107  */
108 extern const char * const OggFLAC__StreamDecoderStateString[];
109
110
111 /***********************************************************************
112  *
113  * class OggFLAC__StreamDecoder
114  *
115  ***********************************************************************/
116
117 struct OggFLAC__StreamDecoderProtected;
118 struct OggFLAC__StreamDecoderPrivate;
119 /** The opaque structure definition for the stream decoder type.
120  *  See the \link oggflac_stream_decoder stream decoder module \endlink
121  *  for a detailed description.
122  */
123 typedef struct {
124         struct OggFLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
125         struct OggFLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
126 } OggFLAC__StreamDecoder;
127
128 /** Signature for the read callback.
129  *  See OggFLAC__stream_decoder_set_read_callback()
130  *  and FLAC__StreamDecoderReadCallback for more info.
131  *
132  * \param  decoder  The decoder instance calling the callback.
133  * \param  buffer   A pointer to a location for the callee to store
134  *                  data to be decoded.
135  * \param  bytes    A pointer to the size of the buffer.
136  * \param  client_data  The callee's client data set through
137  *                      OggFLAC__stream_decoder_set_client_data().
138  * \retval FLAC__StreamDecoderReadStatus
139  *    The callee's return status.
140  */
141 typedef FLAC__StreamDecoderReadStatus (*OggFLAC__StreamDecoderReadCallback)(const OggFLAC__StreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes, void *client_data);
142
143 /** Signature for the write callback.
144  *  See OggFLAC__stream_decoder_set_write_callback()
145  *  and FLAC__StreamDecoderWriteCallback for more info.
146  *
147  * \param  decoder  The decoder instance calling the callback.
148  * \param  frame    The description of the decoded frame.
149  * \param  buffer   An array of pointers to decoded channels of data.
150  * \param  client_data  The callee's client data set through
151  *                      OggFLAC__stream_decoder_set_client_data().
152  * \retval FLAC__StreamDecoderWriteStatus
153  *    The callee's return status.
154  */
155 typedef FLAC__StreamDecoderWriteStatus (*OggFLAC__StreamDecoderWriteCallback)(const OggFLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
156
157 /** Signature for the metadata callback.
158  *  See OggFLAC__stream_decoder_set_metadata_callback()
159  *  and FLAC__StreamDecoderMetadataCallback for more info.
160  *
161  * \param  decoder  The decoder instance calling the callback.
162  * \param  metadata The decoded metadata block.
163  * \param  client_data  The callee's client data set through
164  *                      OggFLAC__stream_decoder_set_client_data().
165  */
166 typedef void (*OggFLAC__StreamDecoderMetadataCallback)(const OggFLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
167
168 /** Signature for the error callback.
169  *  See OggFLAC__stream_decoder_set_error_callback()
170  *  and FLAC__StreamDecoderErrorCallback for more info.
171  *
172  * \param  decoder  The decoder instance calling the callback.
173  * \param  status   The error encountered by the decoder.
174  * \param  client_data  The callee's client data set through
175  *                      OggFLAC__stream_decoder_set_client_data().
176  */
177 typedef void (*OggFLAC__StreamDecoderErrorCallback)(const OggFLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
178
179
180 /***********************************************************************
181  *
182  * Class constructor/destructor
183  *
184  ***********************************************************************/
185
186 /** Create a new stream decoder instance.  The instance is created with
187  *  default settings; see the individual OggFLAC__stream_decoder_set_*()
188  *  functions for each setting's default.
189  *
190  * \retval OggFLAC__StreamDecoder*
191  *    \c NULL if there was an error allocating memory, else the new instance.
192  */
193 OggFLAC__StreamDecoder *OggFLAC__stream_decoder_new();
194
195 /** Free a decoder instance.  Deletes the object pointed to by \a decoder.
196  *
197  * \param decoder  A pointer to an existing decoder.
198  * \assert
199  *    \code decoder != NULL \endcode
200  */
201 void OggFLAC__stream_decoder_delete(OggFLAC__StreamDecoder *decoder);
202
203
204 /***********************************************************************
205  *
206  * Public class method prototypes
207  *
208  ***********************************************************************/
209
210 /** Set the read callback.
211  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_read_callback()
212  *
213  * \note
214  * The callback is mandatory and must be set before initialization.
215  *
216  * \default \c NULL
217  * \param  decoder  An decoder instance to set.
218  * \param  value    See above.
219  * \assert
220  *    \code decoder != NULL \endcode
221  *    \code value != NULL \endcode
222  * \retval FLAC__bool
223  *    \c false if the decoder is already initialized, else \c true.
224  */
225 FLAC__bool OggFLAC__stream_decoder_set_read_callback(OggFLAC__StreamDecoder *decoder, OggFLAC__StreamDecoderReadCallback value);
226
227 /** Set the write callback.
228  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_write_callback()
229  *
230  * \note
231  * The callback is mandatory and must be set before initialization.
232  *
233  * \default \c NULL
234  * \param  decoder  An decoder instance to set.
235  * \param  value    See above.
236  * \assert
237  *    \code decoder != NULL \endcode
238  *    \code value != NULL \endcode
239  * \retval FLAC__bool
240  *    \c false if the decoder is already initialized, else \c true.
241  */
242 FLAC__bool OggFLAC__stream_decoder_set_write_callback(OggFLAC__StreamDecoder *decoder, OggFLAC__StreamDecoderWriteCallback value);
243
244 /** Set the metadata callback.
245  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_metadata_callback()
246  *
247  * \note
248  * The callback is mandatory and must be set before initialization.
249  *
250  * \default \c NULL
251  * \param  decoder  An decoder instance to set.
252  * \param  value    See above.
253  * \assert
254  *    \code decoder != NULL \endcode
255  *    \code value != NULL \endcode
256  * \retval FLAC__bool
257  *    \c false if the decoder is already initialized, else \c true.
258  */
259 FLAC__bool OggFLAC__stream_decoder_set_metadata_callback(OggFLAC__StreamDecoder *decoder, OggFLAC__StreamDecoderMetadataCallback value);
260
261 /** Set the error callback.
262  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_error_callback()
263  *
264  * \note
265  * The callback is mandatory and must be set before initialization.
266  *
267  * \default \c NULL
268  * \param  decoder  An decoder instance to set.
269  * \param  value    See above.
270  * \assert
271  *    \code decoder != NULL \endcode
272  *    \code value != NULL \endcode
273  * \retval FLAC__bool
274  *    \c false if the decoder is already initialized, else \c true.
275  */
276 FLAC__bool OggFLAC__stream_decoder_set_error_callback(OggFLAC__StreamDecoder *decoder, OggFLAC__StreamDecoderErrorCallback value);
277
278 /** Set the client data to be passed back to callbacks.
279  *  This value will be supplied to callbacks in their \a client_data
280  *  argument.
281  *
282  * \default \c NULL
283  * \param  decoder  An decoder instance to set.
284  * \param  value    See above.
285  * \assert
286  *    \code decoder != NULL \endcode
287  * \retval FLAC__bool
288  *    \c false if the decoder is already initialized, else \c true.
289  */
290 FLAC__bool OggFLAC__stream_decoder_set_client_data(OggFLAC__StreamDecoder *decoder, void *value);
291
292 /** Direct the decoder to pass on all metadata blocks of type \a type.
293  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_metadata_respond()
294  *
295  * \default By default, only the \c STREAMINFO block is returned via the
296  *          metadata callback.
297  * \param  decoder  A decoder instance to set.
298  * \param  type     See above.
299  * \assert
300  *    \code decoder != NULL \endcode
301  *    \a type is valid
302  * \retval FLAC__bool
303  *    \c false if the decoder is already initialized, else \c true.
304  */
305 FLAC__bool OggFLAC__stream_decoder_set_metadata_respond(OggFLAC__StreamDecoder *decoder, FLAC__MetadataType type);
306
307 /** Direct the decoder to pass on all APPLICATION metadata blocks of the
308  *  given \a id.
309  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_metadata_respond_application()
310  *
311  * \default By default, only the \c STREAMINFO block is returned via the
312  *          metadata callback.
313  * \param  decoder  A decoder instance to set.
314  * \param  id       See above.
315  * \assert
316  *    \code decoder != NULL \endcode
317  *    \code id != NULL \endcode
318  * \retval FLAC__bool
319  *    \c false if the decoder is already initialized, else \c true.
320  */
321 FLAC__bool OggFLAC__stream_decoder_set_metadata_respond_application(OggFLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
322
323 /** Direct the decoder to pass on all metadata blocks of any type.
324  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_metadata_respond_all()
325  *
326  * \default By default, only the \c STREAMINFO block is returned via the
327  *          metadata callback.
328  * \param  decoder  A decoder instance to set.
329  * \assert
330  *    \code decoder != NULL \endcode
331  * \retval FLAC__bool
332  *    \c false if the decoder is already initialized, else \c true.
333  */
334 FLAC__bool OggFLAC__stream_decoder_set_metadata_respond_all(OggFLAC__StreamDecoder *decoder);
335
336 /** Direct the decoder to filter out all metadata blocks of type \a type.
337  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_metadata_ignore()
338  *
339  * \default By default, only the \c STREAMINFO block is returned via the
340  *          metadata callback.
341  * \param  decoder  A decoder instance to set.
342  * \param  type     See above.
343  * \assert
344  *    \code decoder != NULL \endcode
345  *    \a type is valid
346  * \retval FLAC__bool
347  *    \c false if the decoder is already initialized, else \c true.
348  */
349 FLAC__bool OggFLAC__stream_decoder_set_metadata_ignore(OggFLAC__StreamDecoder *decoder, FLAC__MetadataType type);
350
351 /** Direct the decoder to filter out all APPLICATION metadata blocks of
352  *  the given \a id.
353  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_metadata_ignore_application()
354  *
355  * \default By default, only the \c STREAMINFO block is returned via the
356  *          metadata callback.
357  * \param  decoder  A decoder instance to set.
358  * \param  id       See above.
359  * \assert
360  *    \code decoder != NULL \endcode
361  *    \code id != NULL \endcode
362  * \retval FLAC__bool
363  *    \c false if the decoder is already initialized, else \c true.
364  */
365 FLAC__bool OggFLAC__stream_decoder_set_metadata_ignore_application(OggFLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
366
367 /** Direct the decoder to filter out all metadata blocks of any type.
368  * This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_set_metadata_ignore_all()
369  *
370  * \default By default, only the \c STREAMINFO block is returned via the
371  *          metadata callback.
372  * \param  decoder  A decoder instance to set.
373  * \assert
374  *    \code decoder != NULL \endcode
375  * \retval FLAC__bool
376  *    \c false if the decoder is already initialized, else \c true.
377  */
378 FLAC__bool OggFLAC__stream_decoder_set_metadata_ignore_all(OggFLAC__StreamDecoder *decoder);
379
380 /** Get the current decoder state.
381  *
382  * \param  decoder  A decoder instance to query.
383  * \assert
384  *    \code decoder != NULL \endcode
385  * \retval OggFLAC__StreamDecoderState
386  *    The current decoder state.
387  */
388 OggFLAC__StreamDecoderState OggFLAC__stream_decoder_get_state(const OggFLAC__StreamDecoder *decoder);
389
390 /** Get the state of the underlying FLAC stream decoder.
391  *  Useful when the stream decoder state is
392  *  \c OggFLAC__STREAM_DECODER_FLAC_STREAM_DECODER_ERROR.
393  *
394  * \param  decoder  An decoder instance to query.
395  * \assert
396  *    \code decoder != NULL \endcode
397  * \retval FLAC__StreamDecoderState
398  *    The FLAC stream decoder state.
399  */
400 FLAC__StreamDecoderState OggFLAC__stream_decoder_get_FLAC_stream_decoder_state(const OggFLAC__StreamDecoder *decoder);
401
402 /** This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_get_channels()
403  *
404  * \param  decoder  A decoder instance to query.
405  * \assert
406  *    \code decoder != NULL \endcode
407  * \retval unsigned
408  *    See above.
409  */
410 unsigned OggFLAC__stream_decoder_get_channels(const OggFLAC__StreamDecoder *decoder);
411
412 /** This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_get_channel_assignment()
413  *
414  * \param  decoder  A decoder instance to query.
415  * \assert
416  *    \code decoder != NULL \endcode
417  * \retval OggFLAC__ChannelAssignment
418  *    See above.
419  */
420 FLAC__ChannelAssignment OggFLAC__stream_decoder_get_channel_assignment(const OggFLAC__StreamDecoder *decoder);
421
422 /** This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_get_bits_per_sample()
423  *
424  * \param  decoder  A decoder instance to query.
425  * \assert
426  *    \code decoder != NULL \endcode
427  * \retval unsigned
428  *    See above.
429  */
430 unsigned OggFLAC__stream_decoder_get_bits_per_sample(const OggFLAC__StreamDecoder *decoder);
431
432 /** This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_get_sample_rate()
433  *
434  * \param  decoder  A decoder instance to query.
435  * \assert
436  *    \code decoder != NULL \endcode
437  * \retval unsigned
438  *    See above.
439  */
440 unsigned OggFLAC__stream_decoder_get_sample_rate(const OggFLAC__StreamDecoder *decoder);
441
442 /** This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_get_blocksize()
443  *
444  * \param  decoder  A decoder instance to query.
445  * \assert
446  *    \code decoder != NULL \endcode
447  * \retval unsigned
448  *    See above.
449  */
450 unsigned OggFLAC__stream_decoder_get_blocksize(const OggFLAC__StreamDecoder *decoder);
451
452 /** Initialize the decoder instance.
453  *  Should be called after OggFLAC__stream_decoder_new() and
454  *  OggFLAC__stream_decoder_set_*() but before any of the
455  *  OggFLAC__stream_decoder_process_*() functions.  Will set and return the
456  *  decoder state, which will be OggFLAC__STREAM_DECODER_OK
457  *  if initialization succeeded.
458  *
459  * \param  decoder  An uninitialized decoder instance.
460  * \assert
461  *    \code decoder != NULL \endcode
462  * \retval OggFLAC__StreamDecoderState
463  *    \c OggFLAC__STREAM_DECODER_OK if initialization was
464  *    successful; see OggFLAC__StreamDecoderState for the meanings of other
465  *    return values.
466  */
467 OggFLAC__StreamDecoderState OggFLAC__stream_decoder_init(OggFLAC__StreamDecoder *decoder);
468
469 /** Finish the decoding process.
470  *  Flushes the decoding buffer, releases resources, resets the decoder
471  *  settings to their defaults, and returns the decoder state to
472  *  OggFLAC__STREAM_DECODER_UNINITIALIZED.
473  *
474  *  In the event of a prematurely-terminated decode, it is not strictly
475  *  necessary to call this immediately before OggFLAC__stream_decoder_delete()
476  *  but it is good practice to match every OggFLAC__stream_decoder_init()
477  *  with an OggFLAC__stream_decoder_finish().
478  *
479  * \param  decoder  An uninitialized decoder instance.
480  * \assert
481  *    \code decoder != NULL \endcode
482  */
483 void OggFLAC__stream_decoder_finish(OggFLAC__StreamDecoder *decoder);
484
485 /** This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_flush()
486  *
487  * \param  decoder  A decoder instance.
488  * \assert
489  *    \code decoder != NULL \endcode
490  * \retval FLAC__bool
491  *    \c true if successful, else \c false if a memory allocation
492  *    error occurs.
493  */
494 FLAC__bool OggFLAC__stream_decoder_flush(OggFLAC__StreamDecoder *decoder);
495
496 /** This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_reset()
497  *
498  * \param  decoder  A decoder instance.
499  * \assert
500  *    \code decoder != NULL \endcode
501  * \retval FLAC__bool
502  *    \c true if successful, else \c false if a memory allocation
503  *    error occurs.
504  */
505 FLAC__bool OggFLAC__stream_decoder_reset(OggFLAC__StreamDecoder *decoder);
506
507 /** Decode one metadata block or audio frame.
508  *  This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_process_single()
509  * 
510  * \param  decoder  An initialized decoder instance in the state
511  *                  \c OggFLAC__STREAM_DECODER_OK.
512  * \assert
513  *    \code decoder != NULL \endcode
514  *    \code OggFLAC__stream_decoder_get_state(decoder) == OggFLAC__STREAM_DECODER_OK \endcode
515  * \retval FLAC__bool
516  *    \c false if any read or write error occurred (except
517  *    \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
518  *    in any case, check the decoder state with
519  *    OggFLAC__stream_decoder_get_state() to see what went wrong or to
520  *    check for lost synchronization (a sign of stream corruption).
521  */
522 FLAC__bool OggFLAC__stream_decoder_process_single(OggFLAC__StreamDecoder *decoder);
523
524 /** Decode until the end of the metadata.
525  *  This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_process_until_end_of_metadata()
526  * 
527  * \param  decoder  An initialized decoder instance in the state
528  *                  \c OggFLAC__STREAM_DECODER_OK.
529  * \assert
530  *    \code decoder != NULL \endcode
531  *    \code OggFLAC__stream_decoder_get_state(decoder) == OggFLAC__STREAM_DECODER_OK \endcode
532  * \retval FLAC__bool
533  *    \c false if any read or write error occurred (except
534  *    \c OggFLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
535  *    in any case, check the decoder state with
536  *    OggFLAC__stream_decoder_get_state() to see what went wrong or to
537  *    check for lost synchronization (a sign of stream corruption).
538  */
539 FLAC__bool OggFLAC__stream_decoder_process_until_end_of_metadata(OggFLAC__StreamDecoder *decoder);
540
541 /** Decode until the end of the stream.
542  *  This is inherited from FLAC__StreamDecoder; see FLAC__stream_decoder_process_until_end_of_stream()
543  * 
544  * \param  decoder  An initialized decoder instance in the state
545  *                  \c OggFLAC__STREAM_DECODER_OK.
546  * \assert
547  *    \code decoder != NULL \endcode
548  *    \code OggFLAC__stream_decoder_get_state(decoder) == OggFLAC__STREAM_DECODER_OK \endcode
549  * \retval FLAC__bool
550  *    \c false if any read or write error occurred (except
551  *    \c OggFLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC), else \c true;
552  *    in any case, check the decoder state with
553  *    OggFLAC__stream_decoder_get_state() to see what went wrong or to
554  *    check for lost synchronization (a sign of stream corruption).
555  */
556 FLAC__bool OggFLAC__stream_decoder_process_until_end_of_stream(OggFLAC__StreamDecoder *decoder);
557
558 /* \} */
559
560 #ifdef __cplusplus
561 }
562 #endif
563
564 #endif