pulling trunk
[ardour.git] / libs / libsndfile / src / caf.c
1 /*
2 ** Copyright (C) 2005 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        <stdlib.h>
23 #include        <string.h>
24 #include        <ctype.h>
25
26 #include        "sndfile.h"
27 #include        "sfendian.h"
28 #include        "float_cast.h"
29 #include        "common.h"
30
31 /*------------------------------------------------------------------------------
32 ** Macros to handle big/little endian issues.
33 */
34
35 #define aac_MARKER              MAKE_MARKER ('a', 'a', 'c', ' ')
36 #define alac_MARKER             MAKE_MARKER ('a', 'l', 'a', 'c')
37 #define alaw_MARKER             MAKE_MARKER ('a', 'l', 'a', 'w')
38 #define caff_MARKER             MAKE_MARKER ('c', 'a', 'f', 'f')
39 #define chan_MARKER             MAKE_MARKER ('c', 'h', 'a', 'n')
40 #define data_MARKER             MAKE_MARKER ('d', 'a', 't', 'a')
41 #define desc_MARKER             MAKE_MARKER ('d', 'e', 's', 'c')
42 #define edct_MARKER             MAKE_MARKER ('e', 'd', 'c', 't')
43 #define free_MARKER             MAKE_MARKER ('f', 'r', 'e', 'e')
44 #define ima4_MARKER             MAKE_MARKER ('i', 'm', 'a', '4')
45 #define info_MARKER             MAKE_MARKER ('i', 'n', 'f', 'o')
46 #define inst_MARKER             MAKE_MARKER ('i', 'n', 's', 't')
47 #define kuki_MARKER             MAKE_MARKER ('k', 'u', 'k', 'i')
48 #define lpcm_MARKER             MAKE_MARKER ('l', 'p', 'c', 'm')
49 #define mark_MARKER             MAKE_MARKER ('m', 'a', 'r', 'k')
50 #define midi_MARKER             MAKE_MARKER ('m', 'i', 'd', 'i')
51 #define mp1_MARKER              MAKE_MARKER ('.', 'm', 'p', '1')
52 #define mp2_MARKER              MAKE_MARKER ('.', 'm', 'p', '2')
53 #define mp3_MARKER              MAKE_MARKER ('.', 'm', 'p', '3')
54 #define ovvw_MARKER             MAKE_MARKER ('o', 'v', 'v', 'w')
55 #define pakt_MARKER             MAKE_MARKER ('p', 'a', 'k', 't')
56 #define peak_MARKER             MAKE_MARKER ('p', 'e', 'a', 'k')
57 #define regn_MARKER             MAKE_MARKER ('r', 'e', 'g', 'n')
58 #define strg_MARKER             MAKE_MARKER ('s', 't', 'r', 'g')
59 #define umid_MARKER             MAKE_MARKER ('u', 'm', 'i', 'd')
60 #define uuid_MARKER             MAKE_MARKER ('u', 'u', 'i', 'd')
61 #define ulaw_MARKER             MAKE_MARKER ('u', 'l', 'a', 'w')
62 #define MAC3_MARKER             MAKE_MARKER ('M', 'A', 'C', '3')
63 #define MAC6_MARKER             MAKE_MARKER ('M', 'A', 'C', '6')
64
65 #define CAF_PEAK_CHUNK_SIZE(ch)         (sizeof (int) + ch * (sizeof (float) + 8))
66
67 #define SFE_CAF_NOT_CAF 666
68 #define SFE_CAF_NO_DESC 667
69 #define SFE_CAF_BAD_PEAK 668
70
71 /*------------------------------------------------------------------------------
72 ** Typedefs.
73 */
74
75 typedef struct
76 {       unsigned char srate [8] ;
77         unsigned int fmt_id ;
78         unsigned int fmt_flags ;
79         unsigned int pkt_bytes ;
80         unsigned int pkt_frames ;
81         unsigned int channels_per_frame ;
82         unsigned int bits_per_chan ;
83 } DESC_CHUNK ;
84
85 /*------------------------------------------------------------------------------
86 ** Private static functions.
87 */
88
89 static int      caf_close (SF_PRIVATE *psf) ;
90 static int      caf_read_header (SF_PRIVATE *psf) ;
91 static int      caf_write_header (SF_PRIVATE *psf, int calc_length) ;
92
93 /*------------------------------------------------------------------------------
94 ** Public function.
95 */
96
97 int
98 caf_open (SF_PRIVATE *psf)
99 {       int     subformat, format, error = 0 ;
100
101         if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
102         {       if ((error = caf_read_header (psf)))
103                         return error ;
104                 } ;
105
106         subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
107
108         if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
109         {       if (psf->is_pipe)
110                         return SFE_NO_PIPE_WRITE ;
111
112                 format = psf->sf.format & SF_FORMAT_TYPEMASK ;
113                 if (format != SF_FORMAT_CAF)
114                         return  SFE_BAD_OPEN_FORMAT ;
115
116                 psf->blockwidth = psf->bytewidth * psf->sf.channels ;
117
118                 if (psf->mode != SFM_RDWR || psf->filelength < 44)
119                 {       psf->filelength = 0 ;
120                         psf->datalength = 0 ;
121                         psf->dataoffset = 0 ;
122                         psf->sf.frames = 0 ;
123                         } ;
124
125                 psf->str_flags = SF_STR_ALLOW_START ;
126
127                 /*
128                 **      By default, add the peak chunk to floating point files. Default behaviour
129                 **      can be switched off using sf_command (SFC_SET_PEAK_CHUNK, SF_FALSE).
130                 */
131                 if (psf->mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE))
132                 {       if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL)
133                                 return SFE_MALLOC_FAILED ;
134                         psf->peak_info->peak_loc = SF_PEAK_START ;
135                         } ;
136
137                 if ((error = caf_write_header (psf, SF_FALSE)) != 0)
138                         return error ;
139
140                 psf->write_header = caf_write_header ;
141                 } ;
142
143         psf->container_close = caf_close ;
144         /*psf->command = caf_command ;*/
145
146         switch (subformat)
147         {       case SF_FORMAT_PCM_S8 :
148                 case SF_FORMAT_PCM_16 :
149                 case SF_FORMAT_PCM_24 :
150                 case SF_FORMAT_PCM_32 :
151                                         error = pcm_init (psf) ;
152                                         break ;
153
154                 case SF_FORMAT_ULAW :
155                                         error = ulaw_init (psf) ;
156                                         break ;
157
158                 case SF_FORMAT_ALAW :
159                                         error = alaw_init (psf) ;
160                                         break ;
161
162                 /* Lite remove start */
163                 case SF_FORMAT_FLOAT :
164                                         error = float32_init (psf) ;
165                                         break ;
166
167                 case SF_FORMAT_DOUBLE :
168                                         error = double64_init (psf) ;
169                                         break ;
170                 /* Lite remove end */
171
172                 default :
173                         return SFE_UNSUPPORTED_ENCODING ;
174                 } ;
175
176         return error ;
177 } /* caf_open */
178
179 static int
180 caf_close (SF_PRIVATE *psf)
181 {
182         if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
183                 caf_write_header (psf, SF_TRUE) ;
184
185         return 0 ;
186 } /* caf_close */
187
188 /*------------------------------------------------------------------------------
189 */
190
191 static int
192 decode_desc_chunk (SF_PRIVATE *psf, const DESC_CHUNK *desc)
193 {       int format ;
194
195         psf->sf.channels = desc->channels_per_frame ;
196
197         format = SF_FORMAT_CAF | (psf->endian == SF_ENDIAN_LITTLE ? SF_ENDIAN_LITTLE : 0) ;
198
199         if (desc->fmt_id == lpcm_MARKER && desc->fmt_flags & 1)
200         {       /* Floating point data. */
201                 if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame)
202                 {       psf->bytewidth = 4 ;
203                         return format | SF_FORMAT_FLOAT ;
204                         } ;
205                 if (desc->bits_per_chan == 64 && desc->pkt_bytes == 8 * desc->channels_per_frame)
206                 {       psf->bytewidth = 8 ;
207                         return format | SF_FORMAT_DOUBLE ;
208                         } ;
209                 } ;
210
211         if ((desc->fmt_flags & 1) != 0)
212         {       psf_log_printf (psf, "**** Ooops, 'desc' chunk suggests float data, but other info invalid.\n") ;
213                 return 0 ;
214                 } ;
215
216         if (desc->fmt_id == lpcm_MARKER)
217         {       /* Integer data. */
218                 if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame)
219                 {       psf->bytewidth = 4 ;
220                         return format | SF_FORMAT_PCM_32 ;
221                         } ;
222                 if (desc->bits_per_chan == 24 && desc->pkt_bytes == 3 * desc->channels_per_frame)
223                 {       psf->bytewidth = 3 ;
224                         return format | SF_FORMAT_PCM_24 ;
225                         } ;
226                 if (desc->bits_per_chan == 16 && desc->pkt_bytes == 2 * desc->channels_per_frame)
227                 {       psf->bytewidth = 2 ;
228                         return format | SF_FORMAT_PCM_16 ;
229                         } ;
230                 if (desc->bits_per_chan == 8 && desc->pkt_bytes == 1 * desc->channels_per_frame)
231                 {       psf->bytewidth = 1 ;
232                         return format | SF_FORMAT_PCM_S8 ;
233                         } ;
234                 } ;
235
236         if (desc->fmt_id == alaw_MARKER && desc->bits_per_chan == 8)
237         {       psf->bytewidth = 1 ;
238                 return format | SF_FORMAT_ALAW ;
239                 } ;
240
241         if (desc->fmt_id == ulaw_MARKER && desc->bits_per_chan == 8)
242         {       psf->bytewidth = 1 ;
243                 return format | SF_FORMAT_ULAW ;
244                 } ;
245
246         return 0 ;
247 } /* decode_desc_chunk */
248
249 static int
250 caf_read_header (SF_PRIVATE *psf)
251 {       DESC_CHUNK desc ;
252         sf_count_t chunk_size ;
253         double srate ;
254         short version, flags ;
255         int marker, k, have_data = 0 ;
256
257         memset (&desc, 0, sizeof (desc)) ;
258
259         /* Set position to start of file to begin reading header. */
260         psf_binheader_readf (psf, "pmE2E2", 0, &marker, &version, &flags) ;
261         psf_log_printf (psf, "%M\n  Version : %d\n  Flags   : %x\n", marker, version, flags) ;
262         if (marker != caff_MARKER)
263                 return SFE_CAF_NOT_CAF ;
264
265         psf_binheader_readf (psf, "mE8b", &marker, &chunk_size, psf->u.ucbuf, 8) ;
266         srate = double64_be_read (psf->u.ucbuf) ;
267         LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%5.3f", srate) ;
268         psf_log_printf (psf, "%M : %D\n  Sample rate  : %s\n", marker, chunk_size, psf->u.cbuf) ;
269         if (marker != desc_MARKER)
270                 return SFE_CAF_NO_DESC ;
271
272         if (chunk_size < sizeof (DESC_CHUNK))
273         {       psf_log_printf (psf, "**** Chunk size too small. Should be > 32 bytes.\n") ;
274                 return SFE_MALFORMED_FILE ;
275                 } ;
276
277         psf->sf.samplerate = lrint (srate) ;
278
279         psf_binheader_readf (psf, "mE44444", &desc.fmt_id, &desc.fmt_flags, &desc.pkt_bytes, &desc.pkt_frames,
280                         &desc.channels_per_frame, &desc.bits_per_chan) ;
281         psf_log_printf (psf, "  Format id    : %M\n  Format flags : %x\n  Bytes / packet   : %u\n"
282                         "  Frames / packet  : %u\n  Channels / frame : %u\n  Bits / channel   : %u\n",
283                         desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ;
284
285         if (chunk_size > sizeof (DESC_CHUNK))
286                 psf_binheader_readf (psf, "j", (int) (chunk_size - sizeof (DESC_CHUNK))) ;
287
288         psf->sf.channels = desc.channels_per_frame ;
289
290         while (have_data == 0 && psf_ftell (psf) < psf->filelength - SIGNED_SIZEOF (marker))
291         {       psf_binheader_readf (psf, "mE8", &marker, &chunk_size) ;
292
293                 switch (marker)
294                 {       case peak_MARKER :
295                                 psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
296                                 if (chunk_size != CAF_PEAK_CHUNK_SIZE (psf->sf.channels))
297                                 {       psf_binheader_readf (psf, "j", (int) chunk_size) ;
298                                         psf_log_printf (psf, "*** File PEAK chunk %D should be %d.\n", chunk_size, CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
299                                         return SFE_CAF_BAD_PEAK ;
300                                         } ;
301
302                                 if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL)
303                                         return SFE_MALLOC_FAILED ;
304
305                                 /* read in rest of PEAK chunk. */
306                                 psf_binheader_readf (psf, "E4", & (psf->peak_info->edit_number)) ;
307                                 psf_log_printf (psf, "  edit count : %d\n", psf->peak_info->edit_number) ;
308
309                                 psf_log_printf (psf, "     Ch   Position      Value\n") ;
310                                 for (k = 0 ; k < psf->sf.channels ; k++)
311                                 {       sf_count_t position ;
312                                         float value ;
313
314                                         psf_binheader_readf (psf, "Ef8", &value, &position) ;
315                                         psf->peak_info->peaks [k].value = value ;
316                                         psf->peak_info->peaks [k].position = position ;
317
318                                         LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "    %2d   %-12ld   %g\n", k, (long) position, value) ;
319                                         psf_log_printf (psf, psf->u.cbuf) ;
320                                         } ;
321
322                                 psf->peak_info->peak_loc = SF_PEAK_START ;
323                                 break ;
324
325                         case free_MARKER :
326                                 psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
327                                 psf_binheader_readf (psf, "j", (int) chunk_size) ;
328                                 break ;
329
330                         case data_MARKER :
331                                 psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
332                                 psf_binheader_readf (psf, "E4", &k) ;
333                                 psf_log_printf (psf, "  edit : %u\n", k) ;
334                                 have_data = 1 ;
335                                 break ;
336
337                         default :
338                                 psf_log_printf (psf, " %M : %D (skipped)\n", marker, chunk_size) ;
339                                 psf_binheader_readf (psf, "j", (int) chunk_size) ;
340                                 break ;
341                         } ;
342                 } ;
343
344         if (have_data == 0)
345         {       psf_log_printf (psf, "**** Error, could not find 'data' chunk.\n") ;
346                 return SFE_MALFORMED_FILE ;
347                 } ;
348
349         psf_log_printf (psf, "End\n") ;
350
351         psf->dataoffset = psf_ftell (psf) ;
352         psf->datalength = psf->filelength - psf->dataoffset ;
353         psf->endian = (desc.fmt_flags & 2) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ;
354
355         if ((psf->sf.format = decode_desc_chunk (psf, &desc)) == 0)
356                 return SFE_UNSUPPORTED_ENCODING ;
357
358         if (psf->bytewidth > 0)
359                 psf->sf.frames = psf->datalength / psf->bytewidth ;
360
361         return 0 ;
362 } /* caf_read_header */
363
364 /*------------------------------------------------------------------------------
365 */
366
367 static int
368 caf_write_header (SF_PRIVATE *psf, int calc_length)
369 {       DESC_CHUNK desc ;
370         sf_count_t current, free_len ;
371         int subformat ;
372
373         memset (&desc, 0, sizeof (desc)) ;
374
375         current = psf_ftell (psf) ;
376
377         if (calc_length)
378         {       psf->filelength = psf_get_filelen (psf) ;
379
380                 psf->datalength = psf->filelength - psf->dataoffset ;
381
382                 if (psf->dataend)
383                         psf->datalength -= psf->filelength - psf->dataend ;
384
385                 if (psf->bytewidth > 0)
386                         psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
387                 } ;
388
389         /* Reset the current header length to zero. */
390         psf->header [0] = 0 ;
391         psf->headindex = 0 ;
392         psf_fseek (psf, 0, SEEK_SET) ;
393
394         /* 'caff' marker, version and flags. */
395         psf_binheader_writef (psf, "Em22", caff_MARKER, 1, 0) ;
396
397         /* 'desc' marker and chunk size. */
398         psf_binheader_writef (psf, "Em8", desc_MARKER, (sf_count_t) (sizeof (DESC_CHUNK))) ;
399
400         double64_be_write (1.0 * psf->sf.samplerate, psf->u.ucbuf) ;
401         psf_binheader_writef (psf, "b", psf->u.ucbuf, 8) ;
402
403         subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
404
405         psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
406
407         if (CPU_IS_BIG_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU))
408                 psf->endian = SF_ENDIAN_BIG ;
409         else if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_LITTLE || psf->endian == SF_ENDIAN_CPU))
410                 psf->endian = SF_ENDIAN_LITTLE ;
411
412         if (psf->endian == SF_ENDIAN_LITTLE)
413                 desc.fmt_flags = 2 ;
414         else
415                 psf->endian = SF_ENDIAN_BIG ;
416
417         /* initial section (same for all, it appears) */
418         switch (subformat)
419         {       case SF_FORMAT_PCM_S8 :
420                         desc.fmt_id = lpcm_MARKER ;
421                         psf->bytewidth = 1 ;
422                         desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
423                         desc.pkt_frames = 1 ;
424                         desc.channels_per_frame = psf->sf.channels ;
425                         desc.bits_per_chan = 8 ;
426                         break ;
427
428                 case SF_FORMAT_PCM_16 :
429                         desc.fmt_id = lpcm_MARKER ;
430                         psf->bytewidth = 2 ;
431                         desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
432                         desc.pkt_frames = 1 ;
433                         desc.channels_per_frame = psf->sf.channels ;
434                         desc.bits_per_chan = 16 ;
435                         break ;
436
437                 case SF_FORMAT_PCM_24 :
438                         psf->bytewidth = 3 ;
439                         desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
440                         desc.pkt_frames = 1 ;
441                         desc.channels_per_frame = psf->sf.channels ;
442                         desc.bits_per_chan = 24 ;
443                         desc.fmt_id = lpcm_MARKER ;
444                         break ;
445
446                 case SF_FORMAT_PCM_32 :
447                         desc.fmt_id = lpcm_MARKER ;
448                         psf->bytewidth = 4 ;
449                         desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
450                         desc.pkt_frames = 1 ;
451                         desc.channels_per_frame = psf->sf.channels ;
452                         desc.bits_per_chan = 32 ;
453                         break ;
454
455                 case SF_FORMAT_FLOAT :
456                         desc.fmt_id = lpcm_MARKER ;
457                         desc.fmt_flags |= 1 ;
458                         psf->bytewidth = 4 ;
459                         desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
460                         desc.pkt_frames = 1 ;
461                         desc.channels_per_frame = psf->sf.channels ;
462                         desc.bits_per_chan = 32 ;
463                         break ;
464
465                 case SF_FORMAT_DOUBLE :
466                         desc.fmt_id = lpcm_MARKER ;
467                         desc.fmt_flags |= 1 ;
468                         psf->bytewidth = 8 ;
469                         desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
470                         desc.pkt_frames = 1 ;
471                         desc.channels_per_frame = psf->sf.channels ;
472                         desc.bits_per_chan = 64 ;
473                         break ;
474
475                 case SF_FORMAT_ALAW :
476                         desc.fmt_id = alaw_MARKER ;
477                         psf->bytewidth = 1 ;
478                         desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
479                         desc.pkt_frames = 1 ;
480                         desc.channels_per_frame = psf->sf.channels ;
481                         desc.bits_per_chan = 8 ;
482                         break ;
483
484                 case SF_FORMAT_ULAW :
485                         desc.fmt_id = ulaw_MARKER ;
486                         psf->bytewidth = 1 ;
487                         desc.pkt_bytes = psf->bytewidth * psf->sf.channels ;
488                         desc.pkt_frames = 1 ;
489                         desc.channels_per_frame = psf->sf.channels ;
490                         desc.bits_per_chan = 8 ;
491                         break ;
492
493                 default :
494                         return SFE_UNIMPLEMENTED ;
495                 } ;
496
497         psf_binheader_writef (psf, "mE44444", desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ;
498
499 #if 0
500         if (psf->str_flags & SF_STR_LOCATE_START)
501                 caf_write_strings (psf, SF_STR_LOCATE_START) ;
502 #endif
503
504         if (psf->peak_info != NULL)
505         {       int k ;
506                 psf_binheader_writef (psf, "Em84", peak_MARKER, (sf_count_t) CAF_PEAK_CHUNK_SIZE (psf->sf.channels), psf->peak_info->edit_number) ;
507                 for (k = 0 ; k < psf->sf.channels ; k++)
508                         psf_binheader_writef (psf, "Ef8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
509                 } ;
510
511         /* Add free chunk so that the actual audio data starts at a multiple 0x1000. */
512         free_len = 0x1000 - psf->headindex - 16 - 12 ;
513         while (free_len < 0)
514                 free_len += 0x1000 ;
515         psf_binheader_writef (psf, "Em8z", free_MARKER, free_len, (int) free_len) ;
516
517         psf_binheader_writef (psf, "Em84", data_MARKER, psf->datalength, 0) ;
518
519         psf_fwrite (psf->header, psf->headindex, 1, psf) ;
520         if (psf->error)
521                 return psf->error ;
522
523         psf->dataoffset = psf->headindex ;
524         if (current < psf->dataoffset)
525                 psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
526         else if (current > 0)
527                 psf_fseek (psf, current, SEEK_SET) ;
528
529         return psf->error ;
530 } /* caf_write_header */
531
532 /*
533 ** Do not edit or modify anything in this comment block.
534 ** The arch-tag line is a file identity tag for the GNU Arch
535 ** revision control system.
536 **
537 ** arch-tag: 65883e65-bd3c-4618-9241-d3c02fd630bd
538 */