gst/matroska/ebml-read.c: Don't try to modify read-only data.
[platform/upstream/gst-plugins-good.git] / gst / matroska / ebml-read.c
1 /* GStreamer EBML I/O
2  * (c) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * ebml-read.c: read EBML data from file/stream
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <string.h>
27
28 #include "ebml-read.h"
29 #include "ebml-ids.h"
30
31 GST_DEBUG_CATEGORY_STATIC (ebmlread_debug);
32 #define GST_CAT_DEFAULT ebmlread_debug
33
34 static void gst_ebml_read_class_init (GstEbmlReadClass * klass);
35 static void gst_ebml_read_init (GstEbmlRead * ebml);
36 static GstStateChangeReturn gst_ebml_read_change_state (GstElement * element,
37     GstStateChange transition);
38
39 /* convenience functions */
40 static gboolean gst_ebml_read_peek_bytes (GstEbmlRead * ebml, guint size,
41     GstBuffer ** p_buf);
42 static gboolean gst_ebml_read_pull_bytes (GstEbmlRead * ebml, guint size,
43     GstBuffer ** p_buf);
44
45
46 static GstElementClass *parent_class;   /* NULL */
47
48 GType
49 gst_ebml_read_get_type (void)
50 {
51   static GType gst_ebml_read_type;      /* 0 */
52
53   if (!gst_ebml_read_type) {
54     static const GTypeInfo gst_ebml_read_info = {
55       sizeof (GstEbmlReadClass),
56       NULL,
57       NULL,
58       (GClassInitFunc) gst_ebml_read_class_init,
59       NULL,
60       NULL,
61       sizeof (GstEbmlRead),
62       0,
63       (GInstanceInitFunc) gst_ebml_read_init,
64     };
65
66     gst_ebml_read_type =
67         g_type_register_static (GST_TYPE_ELEMENT, "GstEbmlRead",
68         &gst_ebml_read_info, 0);
69   }
70
71   return gst_ebml_read_type;
72 }
73
74 static void
75 gst_ebml_read_class_init (GstEbmlReadClass * klass)
76 {
77   GstElementClass *gstelement_class = (GstElementClass *) klass;
78
79   parent_class = g_type_class_peek_parent (klass);
80
81   GST_DEBUG_CATEGORY_INIT (ebmlread_debug, "ebmlread",
82       0, "EBML stream helper class");
83
84   gstelement_class->change_state =
85       GST_DEBUG_FUNCPTR (gst_ebml_read_change_state);
86 }
87
88 static void
89 gst_ebml_read_init (GstEbmlRead * ebml)
90 {
91   ebml->sinkpad = NULL;
92   ebml->level = NULL;
93 }
94
95 static GstStateChangeReturn
96 gst_ebml_read_change_state (GstElement * element, GstStateChange transition)
97 {
98   GstStateChangeReturn ret;
99   GstEbmlRead *ebml = GST_EBML_READ (element);
100
101   switch (transition) {
102     case GST_STATE_CHANGE_READY_TO_PAUSED:
103       if (!ebml->sinkpad) {
104         g_return_val_if_reached (GST_STATE_CHANGE_FAILURE);
105       }
106       break;
107     default:
108       break;
109   }
110
111   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
112
113   switch (transition) {
114     case GST_STATE_CHANGE_PAUSED_TO_READY:
115     {
116       g_list_foreach (ebml->level, (GFunc) g_free, NULL);
117       g_list_free (ebml->level);
118       ebml->level = NULL;
119       if (ebml->cached_buffer) {
120         gst_buffer_unref (ebml->cached_buffer);
121         ebml->cached_buffer = NULL;
122       }
123       ebml->offset = 0;
124       break;
125     }
126     default:
127       break;
128   }
129
130   return ret;
131 }
132
133 /*
134  * Return: the amount of levels in the hierarchy that the
135  * current element lies higher than the previous one.
136  * The opposite isn't done - that's auto-done using master
137  * element reading.
138  */
139
140 static guint
141 gst_ebml_read_element_level_up (GstEbmlRead * ebml)
142 {
143   guint num = 0;
144   guint64 pos = ebml->offset;
145
146   while (ebml->level != NULL) {
147     GList *last = g_list_last (ebml->level);
148     GstEbmlLevel *level = last->data;
149
150     if (pos >= level->start + level->length) {
151       ebml->level = g_list_remove (ebml->level, level);
152       g_free (level);
153       num++;
154     } else {
155       break;
156     }
157   }
158
159   return num;
160 }
161
162 /*
163  * Calls pull_range for (offset,size) without advancing our offset
164  */
165 static gboolean
166 gst_ebml_read_peek_bytes (GstEbmlRead * ebml, guint size, GstBuffer ** p_buf)
167 {
168   GstFlowReturn ret;
169
170   /* Caching here actually makes much less difference than one would expect.
171    * We do it mainly to avoid pulling buffers of 1 byte all the time */
172   if (ebml->cached_buffer) {
173     guint64 cache_offset = GST_BUFFER_OFFSET (ebml->cached_buffer);
174     guint cache_size = GST_BUFFER_SIZE (ebml->cached_buffer);
175
176     if (cache_offset <= ebml->offset &&
177         (ebml->offset + size) < (cache_offset + cache_size)) {
178       *p_buf = gst_buffer_create_sub (ebml->cached_buffer,
179           ebml->offset - cache_offset, size);
180       return TRUE;
181     }
182     gst_buffer_unref (ebml->cached_buffer);
183     ebml->cached_buffer = NULL;
184   }
185
186   if (gst_pad_pull_range (ebml->sinkpad, ebml->offset, MAX (size, 64 * 1024),
187           &ebml->cached_buffer) == GST_FLOW_OK &&
188       GST_BUFFER_SIZE (ebml->cached_buffer) >= size) {
189     *p_buf = gst_buffer_create_sub (ebml->cached_buffer, 0, size);
190     return TRUE;
191   }
192
193   ret = gst_pad_pull_range (ebml->sinkpad, ebml->offset, size, p_buf);
194   if (ret != GST_FLOW_OK) {
195     GST_DEBUG ("pull_range returned %d", ret);
196     return FALSE;
197   }
198
199   if (GST_BUFFER_SIZE (*p_buf) < size) {
200     GST_WARNING_OBJECT (ebml, "Dropping short buffer at offset %"
201         G_GUINT64_FORMAT ": wanted %u bytes, got %u bytes", ebml->offset,
202         size, GST_BUFFER_SIZE (*p_buf));
203     gst_buffer_unref (*p_buf);
204     *p_buf = NULL;
205     return FALSE;
206   }
207
208   return TRUE;
209 }
210
211 /*
212  * Calls pull_range for (offset,size) and advances our offset by size
213  */
214 static gboolean
215 gst_ebml_read_pull_bytes (GstEbmlRead * ebml, guint size, GstBuffer ** p_buf)
216 {
217   if (!gst_ebml_read_peek_bytes (ebml, size, p_buf))
218     return FALSE;
219
220   ebml->offset += size;
221   return TRUE;
222 }
223
224 /*
225  * Read: the element content data ID.
226  * Return: FALSE on error.
227  */
228
229 static gboolean
230 gst_ebml_read_element_id (GstEbmlRead * ebml, guint32 * id, guint * level_up)
231 {
232   GstBuffer *buf;
233   gint len_mask = 0x80, read = 1, n = 1;
234   guint32 total;
235   guint8 b;
236
237   if (!gst_ebml_read_peek_bytes (ebml, 1, &buf))
238     return FALSE;
239
240   b = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
241   gst_buffer_unref (buf);
242
243   total = (guint32) b;
244
245   while (read <= 4 && !(total & len_mask)) {
246     read++;
247     len_mask >>= 1;
248   }
249   if (read > 4) {
250     guint64 pos = ebml->offset;
251
252     GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
253         ("Invalid EBML ID size tag (0x%x) at position %llu (0x%llx)",
254             (guint) b, pos, pos));
255     return FALSE;
256   }
257
258   if (!gst_ebml_read_peek_bytes (ebml, read, &buf))
259     return FALSE;
260
261   while (n < read) {
262     b = GST_READ_UINT8 (GST_BUFFER_DATA (buf) + n);
263     total = (total << 8) | b;
264     ++n;
265   }
266
267   *id = total;
268
269   /* level */
270   if (level_up)
271     *level_up = gst_ebml_read_element_level_up (ebml);
272
273   gst_buffer_unref (buf);
274
275   ebml->offset += read;
276   return TRUE;
277 }
278
279 /*
280  * Read: element content length.
281  * Return: the number of bytes read or -1 on error.
282  */
283
284 static gint
285 gst_ebml_read_element_length (GstEbmlRead * ebml, guint64 * length)
286 {
287   GstBuffer *buf;
288   gint len_mask = 0x80, read = 1, n = 1, num_ffs = 0;
289   guint64 total;
290   guint8 b;
291
292   if (!gst_ebml_read_peek_bytes (ebml, 1, &buf))
293     return -1;
294
295   b = GST_READ_UINT8 (GST_BUFFER_DATA (buf));
296   gst_buffer_unref (buf);
297
298   total = (guint64) b;
299
300   while (read <= 8 && !(total & len_mask)) {
301     read++;
302     len_mask >>= 1;
303   }
304   if (read > 8) {
305     guint64 pos = ebml->offset;
306
307     GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
308         ("Invalid EBML length size tag (0x%x) at position %llu (0x%llx)",
309             (guint) b, pos, pos));
310     return -1;
311   }
312
313   if ((total &= (len_mask - 1)) == len_mask - 1)
314     num_ffs++;
315
316   if (!gst_ebml_read_peek_bytes (ebml, read, &buf))
317     return -1;
318
319   while (n < read) {
320     guint8 b = GST_READ_UINT8 (GST_BUFFER_DATA (buf) + n);
321
322     if (b == 0xff)
323       num_ffs++;
324     total = (total << 8) | b;
325     ++n;
326   }
327   gst_buffer_unref (buf);
328
329   if (read == num_ffs)
330     *length = G_MAXUINT64;
331   else
332     *length = total;
333
334   ebml->offset += read;
335
336   return read;
337 }
338
339 /*
340  * Return: the ID of the next element.
341  * Level_up contains the amount of levels that this
342  * next element lies higher than the previous one.
343  */
344
345 gboolean
346 gst_ebml_peek_id (GstEbmlRead * ebml, guint * level_up, guint32 * id)
347 {
348   guint64 off;
349
350   g_assert (level_up);
351
352   off = ebml->offset;           /* save offset */
353
354   if (!gst_ebml_read_element_id (ebml, id, level_up))
355     return FALSE;
356
357   ebml->offset = off;           /* restore offset */
358   return TRUE;
359 }
360
361 /*
362  * Return the length of the stream in bytes
363  */
364
365 gint64
366 gst_ebml_read_get_length (GstEbmlRead * ebml)
367 {
368   GstFormat fmt = GST_FORMAT_BYTES;
369   gint64 end;
370
371   if (!gst_pad_query_duration (GST_PAD_PEER (ebml->sinkpad), &fmt, &end))
372     g_return_val_if_reached (0);        ///// FIXME /////////
373
374   if (fmt != GST_FORMAT_BYTES || end < 0)
375     g_return_val_if_reached (0);        ///// FIXME /////////
376
377   return end;
378 }
379
380 /*
381  * Seek to a given offset.
382  */
383
384 gboolean
385 gst_ebml_read_seek (GstEbmlRead * ebml, guint64 offset)
386 {
387   if (offset >= gst_ebml_read_get_length (ebml))
388     return FALSE;
389
390   ebml->offset = offset;
391
392   return TRUE;
393 }
394
395 /*
396  * Skip the next element.
397  */
398
399 gboolean
400 gst_ebml_read_skip (GstEbmlRead * ebml)
401 {
402   guint64 length;
403   guint32 id;
404
405   if (!gst_ebml_read_element_id (ebml, &id, NULL))
406     return FALSE;
407
408   if (gst_ebml_read_element_length (ebml, &length) < 0)
409     return FALSE;
410
411   ebml->offset += length;
412   return TRUE;
413 }
414
415 /*
416  * Read the next element as a GstBuffer (binary).
417  */
418
419 gboolean
420 gst_ebml_read_buffer (GstEbmlRead * ebml, guint32 * id, GstBuffer ** buf)
421 {
422   guint64 length;
423
424   if (!gst_ebml_read_element_id (ebml, id, NULL))
425     return FALSE;
426
427   if (gst_ebml_read_element_length (ebml, &length) < 0)
428     return FALSE;
429
430   if (length == 0) {
431     *buf = gst_buffer_new ();
432     return TRUE;
433   }
434
435   *buf = NULL;
436   if (!gst_ebml_read_pull_bytes (ebml, (guint) length, buf))
437     return FALSE;
438
439   return TRUE;
440 }
441
442 /*
443  * Read the next element as an unsigned int.
444  */
445
446 gboolean
447 gst_ebml_read_uint (GstEbmlRead * ebml, guint32 * id, guint64 * num)
448 {
449   GstBuffer *buf;
450   guint8 *data;
451   guint size;
452
453   if (!gst_ebml_read_buffer (ebml, id, &buf))
454     return FALSE;
455
456   data = GST_BUFFER_DATA (buf);
457   size = GST_BUFFER_SIZE (buf);
458   if (size < 1 || size > 8) {
459     GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
460         ("Invalid integer element size %d at position %llu (0x%llu)",
461             size, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET (buf)));
462     gst_buffer_unref (buf);
463     return FALSE;
464   }
465   *num = 0;
466   while (size > 0) {
467     *num = (*num << 8) | data[GST_BUFFER_SIZE (buf) - size];
468     size--;
469   }
470
471   gst_buffer_unref (buf);
472
473   return TRUE;
474 }
475
476 /*
477  * Read the next element as a signed int.
478  */
479
480 gboolean
481 gst_ebml_read_sint (GstEbmlRead * ebml, guint32 * id, gint64 * num)
482 {
483   GstBuffer *buf;
484   guint8 *data;
485   guint size, negative = 0, n = 0;
486
487   if (!gst_ebml_read_buffer (ebml, id, &buf))
488     return FALSE;
489
490   size = GST_BUFFER_SIZE (buf);
491   if (size < 1 || size > 8) {
492     GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
493         ("Invalid integer element size %d at position %llu (0x%llx)",
494             size, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET (buf)));
495     gst_buffer_unref (buf);
496     return FALSE;
497   }
498
499   buf = gst_buffer_make_writable (buf);
500
501   data = GST_BUFFER_DATA (buf);
502
503   if (data[0] & 0x80) {
504     negative = 1;
505     data[0] &= ~0x80;
506   }
507
508   *num = 0;
509   while (n < size) {
510     *num = (*num << 8) | data[n++];
511   }
512
513   /* make signed */
514   if (negative) {
515     *num = 0 - *num;
516   }
517
518   gst_buffer_unref (buf);
519
520   return TRUE;
521 }
522
523 /*
524  * Read the next element as a float.
525  */
526
527 gboolean
528 gst_ebml_read_float (GstEbmlRead * ebml, guint32 * id, gdouble * num)
529 {
530   GstBuffer *buf;
531   guint8 *data;
532   guint size;
533
534   if (!gst_ebml_read_buffer (ebml, id, &buf))
535     return FALSE;
536
537   data = GST_BUFFER_DATA (buf);
538   size = GST_BUFFER_SIZE (buf);
539
540   if (size != 4 && size != 8 && size != 10) {
541     GST_ELEMENT_ERROR (ebml, STREAM, DEMUX, (NULL),
542         ("Invalid float element size %d at position %llu (0x%llx)",
543             size, GST_BUFFER_OFFSET (buf), GST_BUFFER_OFFSET (buf)));
544     gst_buffer_unref (buf);
545     return FALSE;
546   }
547
548   if (size == 10) {
549     GST_ELEMENT_ERROR (ebml, CORE, NOT_IMPLEMENTED, (NULL),
550         ("FIXME! 10-byte floats unimplemented"));
551     gst_buffer_unref (buf);
552     return FALSE;
553   }
554
555   if (size == 4) {
556     gfloat f;
557
558 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
559     f = *(gfloat *) data;
560 #else
561     while (size > 0) {
562       ((guint8 *) & f)[size - 1] = data[4 - size];
563       size--;
564     }
565 #endif
566
567     *num = f;
568   } else {
569     gdouble d;
570
571 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
572     d = *(gdouble *) data;
573 #else
574     while (size > 0) {
575       ((guint8 *) & d)[size - 1] = data[8 - size];
576       size--;
577     }
578 #endif
579
580     *num = d;
581   }
582
583   gst_buffer_unref (buf);
584
585   return TRUE;
586 }
587
588 /*
589  * Read the next element as an ASCII string.
590  */
591
592 gboolean
593 gst_ebml_read_ascii (GstEbmlRead * ebml, guint32 * id, gchar ** str)
594 {
595   GstBuffer *buf;
596
597   if (!gst_ebml_read_buffer (ebml, id, &buf))
598     return FALSE;
599
600   *str = g_malloc (GST_BUFFER_SIZE (buf) + 1);
601   memcpy (*str, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
602   (*str)[GST_BUFFER_SIZE (buf)] = '\0';
603
604   gst_buffer_unref (buf);
605
606   return TRUE;
607 }
608
609 /*
610  * Read the next element as a UTF-8 string.
611  */
612
613 gboolean
614 gst_ebml_read_utf8 (GstEbmlRead * ebml, guint32 * id, gchar ** str)
615 {
616   gboolean ret;
617
618 #ifndef GST_DISABLE_GST_DEBUG
619   guint64 oldoff = ebml->offset;
620 #endif
621
622   ret = gst_ebml_read_ascii (ebml, id, str);
623
624   if (str != NULL && *str != NULL && **str != '\0' &&
625       !g_utf8_validate (*str, -1, NULL)) {
626     GST_WARNING ("Invalid UTF-8 string at offset %" G_GUINT64_FORMAT, oldoff);
627   }
628
629   return ret;
630 }
631
632 /*
633  * Read the next element as a date.
634  * Returns the seconds since the unix epoch.
635  */
636
637 gboolean
638 gst_ebml_read_date (GstEbmlRead * ebml, guint32 * id, gint64 * date)
639 {
640   gint64 ebml_date;
641   gboolean res = gst_ebml_read_sint (ebml, id, &ebml_date);
642
643   *date = (ebml_date / GST_SECOND) + GST_EBML_DATE_OFFSET;
644   return res;
645 }
646
647 /*
648  * Read the next element, but only the header. The contents
649  * are supposed to be sub-elements which can be read separately.
650  */
651
652 gboolean
653 gst_ebml_read_master (GstEbmlRead * ebml, guint32 * id)
654 {
655   GstEbmlLevel *level;
656   guint64 length;
657
658   if (!gst_ebml_read_element_id (ebml, id, NULL))
659     return FALSE;
660
661   if (gst_ebml_read_element_length (ebml, &length) < 0)
662     return FALSE;
663
664   /* remember level */
665   level = g_new (GstEbmlLevel, 1);
666   level->start = ebml->offset;
667   level->length = length;
668   ebml->level = g_list_append (ebml->level, level);
669
670   return TRUE;
671 }
672
673 /*
674  * Read the next element as binary data.
675  */
676
677 gboolean
678 gst_ebml_read_binary (GstEbmlRead * ebml,
679     guint32 * id, guint8 ** binary, guint64 * length)
680 {
681   GstBuffer *buf;
682
683   if (!gst_ebml_read_buffer (ebml, id, &buf))
684     return FALSE;
685
686   *length = GST_BUFFER_SIZE (buf);
687   *binary = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
688
689   gst_buffer_unref (buf);
690
691   return TRUE;
692 }
693
694 /*
695  * Read an EBML header.
696  */
697
698 gboolean
699 gst_ebml_read_header (GstEbmlRead * ebml, gchar ** doctype, guint * version)
700 {
701   /* this function is the first to be called */
702   guint32 id;
703   guint level_up;
704
705   /* default init */
706   if (doctype)
707     *doctype = NULL;
708   if (version)
709     *version = 1;
710
711   if (!gst_ebml_peek_id (ebml, &level_up, &id))
712     return FALSE;
713
714   GST_DEBUG_OBJECT (ebml, "id: %08x", GST_READ_UINT32_BE (&id));
715
716   if (level_up != 0 || id != GST_EBML_ID_HEADER) {
717     GST_ELEMENT_ERROR (ebml, STREAM, WRONG_TYPE, (NULL), (NULL));
718     return FALSE;
719   }
720   if (!gst_ebml_read_master (ebml, &id))
721     return FALSE;
722
723   while (TRUE) {
724     if (!gst_ebml_peek_id (ebml, &level_up, &id))
725       return FALSE;
726
727     /* end-of-header */
728     if (level_up)
729       break;
730
731     switch (id) {
732         /* is our read version uptodate? */
733       case GST_EBML_ID_EBMLREADVERSION:{
734         guint64 num;
735
736         if (!gst_ebml_read_uint (ebml, &id, &num))
737           return FALSE;
738         g_assert (id == GST_EBML_ID_EBMLREADVERSION);
739         if (num != GST_EBML_VERSION)
740           return FALSE;
741         break;
742       }
743
744         /* we only handle 8 byte lengths at max */
745       case GST_EBML_ID_EBMLMAXSIZELENGTH:{
746         guint64 num;
747
748         if (!gst_ebml_read_uint (ebml, &id, &num))
749           return FALSE;
750         g_assert (id == GST_EBML_ID_EBMLMAXSIZELENGTH);
751         if (num != sizeof (guint64))
752           return FALSE;
753         break;
754       }
755
756         /* we handle 4 byte IDs at max */
757       case GST_EBML_ID_EBMLMAXIDLENGTH:{
758         guint64 num;
759
760         if (!gst_ebml_read_uint (ebml, &id, &num))
761           return FALSE;
762         g_assert (id == GST_EBML_ID_EBMLMAXIDLENGTH);
763         if (num != sizeof (guint32))
764           return FALSE;
765         break;
766       }
767
768       case GST_EBML_ID_DOCTYPE:{
769         gchar *text;
770
771         if (!gst_ebml_read_ascii (ebml, &id, &text))
772           return FALSE;
773         g_assert (id == GST_EBML_ID_DOCTYPE);
774         if (doctype) {
775           if (doctype)
776             g_free (*doctype);
777           *doctype = text;
778         } else
779           g_free (text);
780         break;
781       }
782
783       case GST_EBML_ID_DOCTYPEREADVERSION:{
784         guint64 num;
785
786         if (!gst_ebml_read_uint (ebml, &id, &num))
787           return FALSE;
788         g_assert (id == GST_EBML_ID_DOCTYPEREADVERSION);
789         if (version)
790           *version = num;
791         break;
792       }
793
794       default:
795         GST_WARNING ("Unknown data type 0x%x in EBML header (ignored)", id);
796         /* pass-through */
797
798         /* we ignore these two, as they don't tell us anything we care about */
799       case GST_EBML_ID_VOID:
800       case GST_EBML_ID_EBMLVERSION:
801       case GST_EBML_ID_DOCTYPEVERSION:
802         if (!gst_ebml_read_skip (ebml))
803           return FALSE;
804         break;
805     }
806   }
807
808   return TRUE;
809 }