root/liboggz/trunk/src/tools/skeleton.c

Revision 3664, 9.2 kB (checked in by conrad, 6 months ago)

skeleton.c::ogg_from_fisbone(): avoid memcpy of NULL fp->message_header_fields.
Fixes ticket:408, reported by j

Line 
1 /*
2  * skeleton.c
3  * author: Tahseen Mohammad
4  */
5
6 /* This file depends on WORDS_BIGENDIAN being defined to 1 if the host
7  * processor stores words with the most significant byte first (like Motorola
8  * and SPARC, unlike Intel and VAX).
9  * On little endian systems, WORDS_BIGENDIAN should be undefined.
10  *
11  * When using GNU Autotools, the correct value will be written into config.h
12  * if the autoconf macro AC_C_BIGENDIAN is called in configure.ac.
13  */
14 #include "config.h"
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include <stdio.h>
19
20 #include <ogg/ogg.h>
21
22 #include "skeleton.h"
23
24 #ifdef WIN32                                                                   
25 #define snprintf _snprintf
26 #endif
27
28 static  unsigned short
29 _le_16 (unsigned short s)
30 {
31   unsigned short ret=s;
32 #ifdef WORDS_BIGENDIAN
33   ret = (s>>8) & 0x00ffU;
34   ret += (s<<8) & 0xff00U;
35 #endif
36   return ret;
37 }
38
39 static  ogg_uint32_t
40 _le_32 (ogg_uint32_t i)
41 {
42    ogg_uint32_t ret=i;
43 #ifdef WORDS_BIGENDIAN
44    ret =  (i>>24);
45    ret += (i>>8) & 0x0000ff00;
46    ret += (i<<8) & 0x00ff0000;
47    ret += (i<<24);
48 #endif
49    return ret;
50 }
51
52 static  ogg_int64_t
53 _le_64 (ogg_int64_t l)
54 {
55   ogg_int64_t ret=l;
56   unsigned char *ucptr = (unsigned char *)&ret;
57 #ifdef WORDS_BIGENDIAN
58   unsigned char temp;
59
60   temp = ucptr [0] ;
61   ucptr [0] = ucptr [7] ;
62   ucptr [7] = temp ;
63
64   temp = ucptr [1] ;
65   ucptr [1] = ucptr [6] ;
66   ucptr [6] = temp ;
67
68   temp = ucptr [2] ;
69   ucptr [2] = ucptr [5] ;
70   ucptr [5] = temp ;
71
72   temp = ucptr [3] ;
73   ucptr [3] = ucptr [4] ;
74   ucptr [4] = temp ;
75
76 #endif
77   return (*(ogg_int64_t *)ucptr);
78 }
79
80 /* write an ogg_page to a file pointer */
81 int write_ogg_page_to_file(ogg_page *og, FILE *out) {
82    int written;
83    
84    written = fwrite(og->header,1, og->header_len, out);
85    if (written > 0)
86      written += fwrite(og->body,1, og->body_len, out);
87
88    return written;
89 }
90
91 int add_message_header_field(fisbone_packet *fp,
92                                         char *header_key,
93                                         char *header_value) {
94
95     /* size of both key and value + ': ' + CRLF */
96     int this_message_size = strlen(header_key) + strlen(header_value) + 4;
97     if (fp->message_header_fields == NULL) {
98         fp->message_header_fields = _ogg_calloc(this_message_size+1, sizeof(char));
99     } else {
100         int new_size = (fp->current_header_size + this_message_size+1) * sizeof(char);
101         fp->message_header_fields = _ogg_realloc(fp->message_header_fields, new_size);
102     }
103     snprintf(fp->message_header_fields + fp->current_header_size,
104                 this_message_size+1,
105                 "%s: %s\r\n",
106                 header_key,
107                 header_value);
108     fp->current_header_size += this_message_size;
109
110     return 0;
111 }
112
113 /* create a ogg_packet from a fishead_packet structure */
114 int ogg_from_fishead(fishead_packet *fp,ogg_packet *op) {
115
116     if (!fp || !op) return -1;
117
118     memset(op, 0, sizeof(*op));
119     op->packet = _ogg_calloc(FISHEAD_SIZE, sizeof(unsigned char));
120     if (!op->packet) return -1;
121
122     memset(op->packet, 0, FISHEAD_SIZE);
123
124     memcpy (op->packet, FISHEAD_IDENTIFIER, 8); /* identifier */
125     *((ogg_uint16_t*)(op->packet+8)) = _le_16 (SKELETON_VERSION_MAJOR); /* version major */
126     *((ogg_uint16_t*)(op->packet+10)) = _le_16 (SKELETON_VERSION_MINOR); /* version minor */
127     *((ogg_int64_t*)(op->packet+12)) = _le_64 (fp->ptime_n); /* presentationtime numerator */
128     *((ogg_int64_t*)(op->packet+20)) = _le_64 (fp->ptime_d); /* presentationtime denominator */
129     *((ogg_int64_t*)(op->packet+28)) = _le_64 (fp->btime_n); /* basetime numerator */
130     *((ogg_int64_t*)(op->packet+36)) = _le_64 (fp->btime_d); /* basetime denominator */
131     /* TODO: UTC time, set to zero for now */
132
133     op->b_o_s = 1;   /* its the first packet of the stream */
134     op->e_o_s = 0;   /* its not the last packet of the stream */
135     op->bytes = FISHEAD_SIZE;  /* length of the packet in bytes */
136
137     return 0;
138 }
139
140 /* create a ogg_packet from a fisbone_packet structure.
141  * call this method after the fisbone_packet is filled and all message header fields are added
142  * by calling add_message_header_field method.
143  */
144 int ogg_from_fisbone(fisbone_packet *fp,ogg_packet *op) {
145    
146     int packet_size;
147
148     if (!fp || !op) return -1;
149
150     packet_size = FISBONE_SIZE + fp->current_header_size;
151
152     memset (op, 0, sizeof (*op));       
153     op->packet = _ogg_calloc (packet_size, sizeof(unsigned char));
154     if (!op->packet) return -1;
155
156     memset (op->packet, 0, packet_size);
157     memcpy (op->packet, FISBONE_IDENTIFIER, 8); /* identifier */
158     *((ogg_uint32_t*)(op->packet+8)) = _le_32 (FISBONE_MESSAGE_HEADER_OFFSET); /* offset of the message header fields */
159     *((ogg_uint32_t*)(op->packet+12)) = _le_32 (fp->serial_no); /* serialno of the respective stream */
160     *((ogg_uint32_t*)(op->packet+16)) = _le_32 (fp->nr_header_packet); /* number of header packets */
161     *((ogg_int64_t*)(op->packet+20)) = _le_64 (fp->granule_rate_n); /* granulrate numerator */
162     *((ogg_int64_t*)(op->packet+28)) = _le_64 (fp->granule_rate_d); /* granulrate denominator */
163     *((ogg_int64_t*)(op->packet+36)) = _le_64 (fp->start_granule); /* start granule */
164     *((ogg_uint32_t*)(op->packet+44)) = _le_32 (fp->preroll); /* preroll, for theora its 0 */
165     *(op->packet+48) = fp->granule_shift; /* granule shift */
166     if (fp->message_header_fields)
167       memcpy((op->packet+FISBONE_SIZE), fp->message_header_fields, fp->current_header_size);
168
169
170     op->b_o_s = 0;
171     op->e_o_s = 0;
172     op->bytes = packet_size; /* size of the packet in bytes */
173
174     return 0;
175 }
176
177 /* fills up a fishead_packet from memory */
178 static int fishead_from_data (const unsigned char * data, int len, fishead_packet *fp) {
179     if (!data) return -1;
180
181     if (memcmp(data, FISHEAD_IDENTIFIER, 8))
182       return -1;
183
184     fp->version_major = _le_16 (*((ogg_uint16_t*)(data+8))); /* version major */
185     fp->version_minor = _le_16 (*((ogg_uint16_t*)(data+10))); /* version minor */
186     fp->ptime_n = _le_64 (*((ogg_int64_t*)(data+12))); /* presentationtime numerator */
187     fp->ptime_d = _le_64 (*((ogg_int64_t*)(data+20))); /* presentationtime denominator */
188     fp->btime_n = _le_64 (*((ogg_int64_t*)(data+28))); /* basetime numerator */
189     fp->btime_d = _le_64 (*((ogg_int64_t*)(data+36))); /* basetime denominator */
190     memcpy(fp->UTC, data+44, 20);
191
192     return 0;
193 }
194
195 /* fills up a fishead_packet from a fishead ogg_packet of a skeleton bistream */
196 int fishead_from_ogg (ogg_packet *op, fishead_packet *fp) {
197     return fishead_from_data (op->packet, op->bytes, fp);
198 }
199
200 /* fills up a fishead_packet from a fishead ogg_page of a skeleton bistream */
201 int fishead_from_ogg_page (const ogg_page *og, fishead_packet *fp) {
202     return fishead_from_data (og->body, og->body_len, fp);
203 }
204
205 /* fills up a fisbone_packet from memory */
206 static int fisbone_from_data (const unsigned char * data, int len, fisbone_packet *fp) {
207
208     if (!fp) return -1;
209
210     if (memcmp(data, FISBONE_IDENTIFIER, 8))
211           return -1;
212
213     fp->serial_no = _le_32 (*((ogg_uint32_t*)(data+12))); /* serialno of the stream represented by this fisbone packet */
214     fp->nr_header_packet = _le_32 (*((ogg_uint32_t*)(data+16))); /* number of header packets */
215     fp->granule_rate_n = _le_64 (*((ogg_int64_t*)(data+20))); /* granulrate numerator */
216     fp->granule_rate_d = _le_64 (*((ogg_int64_t*)(data+28))); /* granulrate denominator */
217     fp->start_granule = _le_64 (*((ogg_int64_t*)(data+36))); /* start granule */
218     fp->preroll = _le_32 (*((ogg_uint32_t*)(data+44))); /* preroll, for theora its 0 */
219     fp->granule_shift = *(data+48); /* granule shift */
220     fp->current_header_size = len - FISBONE_SIZE;
221     fp->message_header_fields = _ogg_calloc(fp->current_header_size+1, sizeof(char));
222     if (!fp->message_header_fields) return -1;
223     memcpy(fp->message_header_fields, data+FISBONE_SIZE, fp->current_header_size);
224
225     return 0;
226 }
227
228 /* fills up a fisbone_packet from a fisbone ogg_packet of a skeleton bitstream */
229 int fisbone_from_ogg (ogg_packet *op, fisbone_packet *fp) {
230   return fisbone_from_data (op->packet, op->bytes, fp);
231 }
232
233 /* fills up a fisbone_packet from a fisbone ogg_page of a skeleton bistream */
234 int fisbone_from_ogg_page (const ogg_page *og, fisbone_packet *fp) {
235     return fisbone_from_data (og->body, og->body_len, fp);
236 }
237
238 int fisbone_clear(fisbone_packet *fp)
239 {
240     if (!fp) return -1;
241     _ogg_free(fp->message_header_fields);
242     return 0;
243 }
244
245 int add_fishead_to_stream(ogg_stream_state *os, fishead_packet *fp) {
246
247     ogg_packet op;
248     int ret;
249
250     ret = ogg_from_fishead(fp, &op);
251     if (ret<0) return ret;
252     ogg_stream_packetin(os, &op);
253     _ogg_free(op.packet);
254
255     return 0;
256 }
257
258 int add_fisbone_to_stream(ogg_stream_state *os, fisbone_packet *fp) {
259
260     ogg_packet op;
261     int ret;
262
263     ret = ogg_from_fisbone(fp, &op);
264     if (ret<0) return ret;
265     ogg_stream_packetin(os, &op);
266     _ogg_free(op.packet);
267
268     return 0;
269 }
270
271 int add_eos_packet_to_stream(ogg_stream_state *os) {
272
273     ogg_packet op;
274
275     memset (&op, 0, sizeof(op));
276     op.e_o_s = 1;
277     ogg_stream_packetin(os, &op);
278
279     return 0;
280 }
281
282 int flush_ogg_stream_to_file(ogg_stream_state *os, FILE *out) {
283
284     ogg_page og;
285     int result;
286
287     while((result = ogg_stream_flush(os, &og)))
288     {
289         if(!result) break;
290         result = write_ogg_page_to_file(&og, out);
291         if(result != og.header_len + og.body_len)
292             return 1;
293     }
294
295     return 0;
296 }
Note: See TracBrowser for help on using the browser.