annotate tremor/info.c @ 16513:68890ac57391

Reflect recent changes to the the pan audio filter syntax and behavior in the documentation, patch by Reimar Doeffinger with some fixes by me.
author diego
date Sun, 18 Sep 2005 11:40:06 +0000
parents 8631a3803289
children cd6b211be811
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
14280
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
1 /********************************************************************
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
2 * *
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
4 * *
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
5 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
6 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
7 * ALL REDISTRIBUTION RIGHTS RESERVED. *
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
8 * *
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
9 ********************************************************************
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
10
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
11 function: maintain the info structure, info <-> header packets
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
12
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
13 ********************************************************************/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
14
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
15 /* general handling of the header and the vorbis_info structure (and
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
16 substructures) */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
17
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
18 #include <stdlib.h>
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
19 #include <string.h>
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
20 #include <ctype.h>
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
21 #include "ogg.h"
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
22 #include "ivorbiscodec.h"
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
23 #include "codec_internal.h"
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
24 #include "codebook.h"
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
25 #include "registry.h"
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
26 #include "window.h"
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
27 #include "misc.h"
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
28 #include "os.h"
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
29
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
30 /* helpers */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
31 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
32 while(bytes--){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
33 *buf++=oggpack_read(o,8);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
34 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
35 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
36
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
37 void vorbis_comment_init(vorbis_comment *vc){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
38 memset(vc,0,sizeof(*vc));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
39 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
40
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
41 /* This is more or less the same as strncasecmp - but that doesn't exist
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
42 * everywhere, and this is a fairly trivial function, so we include it */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
43 static int tagcompare(const char *s1, const char *s2, int n){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
44 int c=0;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
45 while(c < n){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
46 if(toupper(s1[c]) != toupper(s2[c]))
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
47 return !0;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
48 c++;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
49 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
50 return 0;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
51 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
52
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
53 char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
54 long i;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
55 int found = 0;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
56 int taglen = strlen(tag)+1; /* +1 for the = we append */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
57 char *fulltag = (char *)alloca(taglen+ 1);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
58
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
59 strcpy(fulltag, tag);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
60 strcat(fulltag, "=");
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
61
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
62 for(i=0;i<vc->comments;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
63 if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
64 if(count == found)
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
65 /* We return a pointer to the data, not a copy */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
66 return vc->user_comments[i] + taglen;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
67 else
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
68 found++;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
69 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
70 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
71 return NULL; /* didn't find anything */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
72 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
73
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
74 int vorbis_comment_query_count(vorbis_comment *vc, char *tag){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
75 int i,count=0;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
76 int taglen = strlen(tag)+1; /* +1 for the = we append */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
77 char *fulltag = (char *)alloca(taglen+1);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
78 strcpy(fulltag,tag);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
79 strcat(fulltag, "=");
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
80
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
81 for(i=0;i<vc->comments;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
82 if(!tagcompare(vc->user_comments[i], fulltag, taglen))
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
83 count++;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
84 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
85
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
86 return count;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
87 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
88
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
89 void vorbis_comment_clear(vorbis_comment *vc){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
90 if(vc){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
91 long i;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
92 for(i=0;i<vc->comments;i++)
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
93 if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
94 if(vc->user_comments)_ogg_free(vc->user_comments);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
95 if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
96 if(vc->vendor)_ogg_free(vc->vendor);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
97 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
98 memset(vc,0,sizeof(*vc));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
99 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
100
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
101 /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
102 They may be equal, but short will never ge greater than long */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
103 int vorbis_info_blocksize(vorbis_info *vi,int zo){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
104 codec_setup_info *ci = (codec_setup_info *)vi->codec_setup;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
105 return ci ? ci->blocksizes[zo] : -1;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
106 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
107
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
108 /* used by synthesis, which has a full, alloced vi */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
109 void vorbis_info_init(vorbis_info *vi){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
110 memset(vi,0,sizeof(*vi));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
111 vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
112 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
113
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
114 void vorbis_info_clear(vorbis_info *vi){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
115 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
116 int i;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
117
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
118 if(ci){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
119
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
120 for(i=0;i<ci->modes;i++)
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
121 if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
122
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
123 for(i=0;i<ci->maps;i++) /* unpack does the range checking */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
124 _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
125
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
126 for(i=0;i<ci->floors;i++) /* unpack does the range checking */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
127 _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
128
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
129 for(i=0;i<ci->residues;i++) /* unpack does the range checking */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
130 _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
131
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
132 for(i=0;i<ci->books;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
133 if(ci->book_param[i]){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
134 /* knows if the book was not alloced */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
135 vorbis_staticbook_destroy(ci->book_param[i]);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
136 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
137 if(ci->fullbooks)
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
138 vorbis_book_clear(ci->fullbooks+i);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
139 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
140 if(ci->fullbooks)
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
141 _ogg_free(ci->fullbooks);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
142
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
143 _ogg_free(ci);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
144 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
145
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
146 memset(vi,0,sizeof(*vi));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
147 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
148
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
149 /* Header packing/unpacking ********************************************/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
150
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
151 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
152 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
153 if(!ci)return(OV_EFAULT);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
154
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
155 vi->version=oggpack_read(opb,32);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
156 if(vi->version!=0)return(OV_EVERSION);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
157
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
158 vi->channels=oggpack_read(opb,8);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
159 vi->rate=oggpack_read(opb,32);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
160
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
161 vi->bitrate_upper=oggpack_read(opb,32);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
162 vi->bitrate_nominal=oggpack_read(opb,32);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
163 vi->bitrate_lower=oggpack_read(opb,32);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
164
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
165 ci->blocksizes[0]=1<<oggpack_read(opb,4);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
166 ci->blocksizes[1]=1<<oggpack_read(opb,4);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
167
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
168 if(vi->rate<1)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
169 if(vi->channels<1)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
170 if(ci->blocksizes[0]<64)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
171 if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
172 if(ci->blocksizes[1]>8192)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
173
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
174 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
175
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
176 return(0);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
177 err_out:
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
178 vorbis_info_clear(vi);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
179 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
180 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
181
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
182 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
183 int i;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
184 int vendorlen=oggpack_read(opb,32);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
185 if(vendorlen<0)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
186 vc->vendor=(char *)_ogg_calloc(vendorlen+1,1);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
187 _v_readstring(opb,vc->vendor,vendorlen);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
188 vc->comments=oggpack_read(opb,32);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
189 if(vc->comments<0)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
190 vc->user_comments=(char **)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
191 vc->comment_lengths=(int *)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
192
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
193 for(i=0;i<vc->comments;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
194 int len=oggpack_read(opb,32);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
195 if(len<0)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
196 vc->comment_lengths[i]=len;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
197 vc->user_comments[i]=(char *)_ogg_calloc(len+1,1);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
198 _v_readstring(opb,vc->user_comments[i],len);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
199 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
200 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
201
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
202 return(0);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
203 err_out:
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
204 vorbis_comment_clear(vc);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
205 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
206 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
207
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
208 /* all of the real encoding details are here. The modes, books,
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
209 everything */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
210 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
211 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
212 int i;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
213 if(!ci)return(OV_EFAULT);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
214
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
215 /* codebooks */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
216 ci->books=oggpack_read(opb,8)+1;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
217 /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
218 for(i=0;i<ci->books;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
219 ci->book_param[i]=(static_codebook *)_ogg_calloc(1,sizeof(*ci->book_param[i]));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
220 if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
221 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
222
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
223 /* time backend settings */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
224 ci->times=oggpack_read(opb,6)+1;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
225 /*ci->time_type=_ogg_malloc(ci->times*sizeof(*ci->time_type));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
226 /*ci->time_param=_ogg_calloc(ci->times,sizeof(void *));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
227 for(i=0;i<ci->times;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
228 ci->time_type[i]=oggpack_read(opb,16);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
229 if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
230 /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
231 Vorbis I has no time backend */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
232 /*if(!ci->time_param[i])goto err_out;*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
233 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
234
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
235 /* floor backend settings */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
236 ci->floors=oggpack_read(opb,6)+1;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
237 /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
238 /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
239 for(i=0;i<ci->floors;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
240 ci->floor_type[i]=oggpack_read(opb,16);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
241 if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
242 ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
243 if(!ci->floor_param[i])goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
244 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
245
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
246 /* residue backend settings */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
247 ci->residues=oggpack_read(opb,6)+1;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
248 /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
249 /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
250 for(i=0;i<ci->residues;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
251 ci->residue_type[i]=oggpack_read(opb,16);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
252 if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
253 ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
254 if(!ci->residue_param[i])goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
255 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
256
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
257 /* map backend settings */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
258 ci->maps=oggpack_read(opb,6)+1;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
259 /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
260 /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
261 for(i=0;i<ci->maps;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
262 ci->map_type[i]=oggpack_read(opb,16);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
263 if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
264 ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
265 if(!ci->map_param[i])goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
266 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
267
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
268 /* mode settings */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
269 ci->modes=oggpack_read(opb,6)+1;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
270 /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
271 for(i=0;i<ci->modes;i++){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
272 ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i]));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
273 ci->mode_param[i]->blockflag=oggpack_read(opb,1);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
274 ci->mode_param[i]->windowtype=oggpack_read(opb,16);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
275 ci->mode_param[i]->transformtype=oggpack_read(opb,16);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
276 ci->mode_param[i]->mapping=oggpack_read(opb,8);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
277
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
278 if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
279 if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
280 if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
281 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
282
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
283 if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
284
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
285 return(0);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
286 err_out:
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
287 vorbis_info_clear(vi);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
288 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
289 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
290
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
291 /* The Vorbis header is in three packets; the initial small packet in
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
292 the first page that identifies basic parameters, a second packet
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
293 with bitstream comments and a third packet that holds the
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
294 codebook. */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
295
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
296 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
297 oggpack_buffer opb;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
298
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
299 if(op){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
300 oggpack_readinit(&opb,op->packet,op->bytes);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
301
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
302 /* Which of the three types of header is this? */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
303 /* Also verify header-ness, vorbis */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
304 {
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
305 char buffer[6];
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
306 int packtype=oggpack_read(&opb,8);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
307 memset(buffer,0,6);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
308 _v_readstring(&opb,buffer,6);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
309 if(memcmp(buffer,"vorbis",6)){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
310 /* not a vorbis header */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
311 return(OV_ENOTVORBIS);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
312 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
313 switch(packtype){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
314 case 0x01: /* least significant *bit* is read first */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
315 if(!op->b_o_s){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
316 /* Not the initial packet */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
317 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
318 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
319 if(vi->rate!=0){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
320 /* previously initialized info header */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
321 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
322 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
323
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
324 return(_vorbis_unpack_info(vi,&opb));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
325
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
326 case 0x03: /* least significant *bit* is read first */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
327 if(vi->rate==0){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
328 /* um... we didn't get the initial header */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
329 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
330 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
331
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
332 return(_vorbis_unpack_comment(vc,&opb));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
333
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
334 case 0x05: /* least significant *bit* is read first */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
335 if(vi->rate==0 || vc->vendor==NULL){
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
336 /* um... we didn;t get the initial header or comments yet */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
337 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
338 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
339
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
340 return(_vorbis_unpack_books(vi,&opb));
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
341
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
342 default:
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
343 /* Not a valid vorbis header type */
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
344 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
345 break;
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
346 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
347 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
348 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
349 return(OV_EBADHEADER);
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
350 }
8631a3803289 internal Tremor decoder for Ogg/Vorbis
henry
parents:
diff changeset
351