introspection: assorted introspection and documentation fixes in base
[platform/upstream/gstreamer.git] / libs / gst / base / gstbytewriter.c
1 /* GStreamer byte writer
2  *
3  * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #define GST_BYTE_WRITER_DISABLE_INLINES
26 #include "gstbytewriter.h"
27
28 /**
29  * SECTION:gstbytewriter
30  * @short_description: Writes different integer, string and floating point
31  *     types to a memory buffer and allows reading
32  *
33  * #GstByteWriter provides a byte writer and reader that can write/read different
34  * integer and floating point types to/from a memory buffer. It provides functions
35  * for writing/reading signed/unsigned, little/big endian integers of 8, 16, 24,
36  * 32 and 64 bits and functions for reading little/big endian floating points numbers of
37  * 32 and 64 bits. It also provides functions to write/read NUL-terminated strings
38  * in various character encodings.
39  */
40
41 /**
42  * gst_byte_writer_new:
43  *
44  * Creates a new, empty #GstByteWriter instance
45  *
46  * Free-function: gst_byte_writer_free
47  *
48  * Returns: (transfer full): a new, empty #GstByteWriter instance
49  *
50  * Since: 0.10.26
51  */
52 GstByteWriter *
53 gst_byte_writer_new (void)
54 {
55   GstByteWriter *ret = g_slice_new0 (GstByteWriter);
56
57   ret->owned = TRUE;
58   return ret;
59 }
60
61 /**
62  * gst_byte_writer_new_with_size:
63  * @size: Initial size of data
64  * @fixed: If %TRUE the data can't be reallocated
65  *
66  * Creates a new #GstByteWriter instance with the given
67  * initial data size.
68  *
69  * Free-function: gst_byte_writer_free
70  *
71  * Returns: (transfer full): a new #GstByteWriter instance
72  *
73  * Since: 0.10.26
74  */
75 GstByteWriter *
76 gst_byte_writer_new_with_size (guint size, gboolean fixed)
77 {
78   GstByteWriter *ret = gst_byte_writer_new ();
79
80   ret->alloc_size = size;
81   ret->parent.data = g_malloc (ret->alloc_size);
82   ret->fixed = fixed;
83   ret->owned = TRUE;
84
85   return ret;
86 }
87
88 /**
89  * gst_byte_writer_new_with_data:
90  * @data: Memory area for writing
91  * @size: Size of @data in bytes
92  * @initialized: If %TRUE the complete data can be read from the beginning
93  *
94  * Creates a new #GstByteWriter instance with the given
95  * memory area. If @initialized is %TRUE it is possible to
96  * read @size bytes from the #GstByteWriter from the beginning.
97  *
98  * Free-function: gst_byte_writer_free
99  *
100  * Returns: (transfer full): a new #GstByteWriter instance
101  *
102  * Since: 0.10.26
103  */
104 GstByteWriter *
105 gst_byte_writer_new_with_data (guint8 * data, guint size, gboolean initialized)
106 {
107   GstByteWriter *ret = gst_byte_writer_new ();
108
109   ret->parent.data = data;
110   ret->parent.size = (initialized) ? size : 0;
111   ret->alloc_size = size;
112   ret->fixed = TRUE;
113   ret->owned = FALSE;
114
115   return ret;
116 }
117
118 /**
119  * gst_byte_writer_init:
120  * @writer: #GstByteWriter instance
121  *
122  * Initializes @writer to an empty instance
123  *
124  * Since: 0.10.26
125  */
126 void
127 gst_byte_writer_init (GstByteWriter * writer)
128 {
129   g_return_if_fail (writer != NULL);
130
131   memset (writer, 0, sizeof (GstByteWriter));
132
133   writer->owned = TRUE;
134 }
135
136 /**
137  * gst_byte_writer_init_with_size:
138  * @writer: #GstByteWriter instance
139  * @size: Initial size of data
140  * @fixed: If %TRUE the data can't be reallocated
141  *
142  * Initializes @writer with the given initial data size.
143  *
144  * Since: 0.10.26
145  */
146 void
147 gst_byte_writer_init_with_size (GstByteWriter * writer, guint size,
148     gboolean fixed)
149 {
150   g_return_if_fail (writer != NULL);
151
152   gst_byte_writer_init (writer);
153
154   writer->parent.data = g_malloc (size);
155   writer->alloc_size = size;
156   writer->fixed = fixed;
157   writer->owned = TRUE;
158 }
159
160 /**
161  * gst_byte_writer_init_with_data:
162  * @writer: #GstByteWriter instance
163  * @data: (array length=size) (transfer none): Memory area for writing
164  * @size: Size of @data in bytes
165  * @initialized: If %TRUE the complete data can be read from the beginning
166  *
167  * Initializes @writer with the given
168  * memory area. If @initialized is %TRUE it is possible to
169  * read @size bytes from the #GstByteWriter from the beginning.
170  *
171  * Since: 0.10.26
172  */
173 void
174 gst_byte_writer_init_with_data (GstByteWriter * writer, guint8 * data,
175     guint size, gboolean initialized)
176 {
177   g_return_if_fail (writer != NULL);
178
179   gst_byte_writer_init (writer);
180
181   writer->parent.data = data;
182   writer->parent.size = (initialized) ? size : 0;
183   writer->alloc_size = size;
184   writer->fixed = TRUE;
185   writer->owned = FALSE;
186 }
187
188 /**
189  * gst_byte_writer_reset:
190  * @writer: #GstByteWriter instance
191  *
192  * Resets @writer and frees the data if it's
193  * owned by @writer.
194  *
195  * Since: 0.10.26
196  */
197 void
198 gst_byte_writer_reset (GstByteWriter * writer)
199 {
200   g_return_if_fail (writer != NULL);
201
202   if (writer->owned)
203     g_free ((guint8 *) writer->parent.data);
204   memset (writer, 0, sizeof (GstByteWriter));
205 }
206
207 /**
208  * gst_byte_writer_reset_and_get_data:
209  * @writer: #GstByteWriter instance
210  *
211  * Resets @writer and returns the current data.
212  *
213  * Free-function: g_free
214  *
215  * Returns: (transfer full): the current data. g_free() after usage.
216  *
217  * Since: 0.10.26
218  */
219 guint8 *
220 gst_byte_writer_reset_and_get_data (GstByteWriter * writer)
221 {
222   guint8 *data;
223
224   g_return_val_if_fail (writer != NULL, NULL);
225
226   data = (guint8 *) writer->parent.data;
227   if (!writer->owned)
228     data = g_memdup (data, writer->parent.size);
229   writer->parent.data = NULL;
230   gst_byte_writer_reset (writer);
231
232   return data;
233 }
234
235 /**
236  * gst_byte_writer_reset_and_get_buffer:
237  * @writer: #GstByteWriter instance
238  *
239  * Resets @writer and returns the current data as buffer.
240  *
241  * Free-function: gst_buffer_unref
242  *
243  * Returns: (transfer full): the current data as buffer. gst_buffer_unref()
244  *     after usage.
245  *
246  * Since: 0.10.26
247  */
248 GstBuffer *
249 gst_byte_writer_reset_and_get_buffer (GstByteWriter * writer)
250 {
251   GstBuffer *buffer;
252   gpointer data;
253   gsize size;
254
255   g_return_val_if_fail (writer != NULL, NULL);
256
257   size = writer->parent.size;
258   data = gst_byte_writer_reset_and_get_data (writer);
259
260   buffer = gst_buffer_new ();
261   if (data != NULL) {
262     gst_buffer_append_memory (buffer,
263         gst_memory_new_wrapped (0, data, size, 0, size, data, g_free));
264   }
265
266   return buffer;
267 }
268
269 /**
270  * gst_byte_writer_free:
271  * @writer: (in) (transfer full): #GstByteWriter instance
272  *
273  * Frees @writer and all memory allocated by it.
274  *
275  * Since: 0.10.26
276  */
277 void
278 gst_byte_writer_free (GstByteWriter * writer)
279 {
280   g_return_if_fail (writer != NULL);
281
282   gst_byte_writer_reset (writer);
283   g_slice_free (GstByteWriter, writer);
284 }
285
286 /**
287  * gst_byte_writer_free_and_get_data:
288  * @writer: (in) (transfer full): #GstByteWriter instance
289  *
290  * Frees @writer and all memory allocated by it except
291  * the current data, which is returned.
292  *
293  * Free-function: g_free
294  *
295  * Returns: (transfer full): the current data. g_free() after usage.
296  *
297  * Since: 0.10.26
298  */
299 guint8 *
300 gst_byte_writer_free_and_get_data (GstByteWriter * writer)
301 {
302   guint8 *data;
303
304   g_return_val_if_fail (writer != NULL, NULL);
305
306   data = gst_byte_writer_reset_and_get_data (writer);
307   g_slice_free (GstByteWriter, writer);
308
309   return data;
310 }
311
312 /**
313  * gst_byte_writer_free_and_get_buffer:
314  * @writer: (in) (transfer full): #GstByteWriter instance
315  *
316  * Frees @writer and all memory allocated by it except
317  * the current data, which is returned as #GstBuffer.
318  *
319  * Free-function: gst_buffer_unref
320  *
321  * Returns: (transfer full): the current data as buffer. gst_buffer_unref()
322  *     after usage.
323  *
324  * Since: 0.10.26
325  */
326 GstBuffer *
327 gst_byte_writer_free_and_get_buffer (GstByteWriter * writer)
328 {
329   GstBuffer *buffer;
330
331   g_return_val_if_fail (writer != NULL, NULL);
332
333   buffer = gst_byte_writer_reset_and_get_buffer (writer);
334   g_slice_free (GstByteWriter, writer);
335
336   return buffer;
337 }
338
339 /**
340  * gst_byte_writer_get_remaining:
341  * @writer: #GstByteWriter instance
342  *
343  * Returns the remaining size of data that can still be written. If
344  * -1 is returned the remaining size is only limited by system resources.
345  *
346  * Returns: the remaining size of data that can still be written
347  *
348  * Since: 0.10.26
349  */
350 guint
351 gst_byte_writer_get_remaining (const GstByteWriter * writer)
352 {
353   g_return_val_if_fail (writer != NULL, -1);
354
355   if (!writer->fixed)
356     return -1;
357   else
358     return writer->alloc_size - writer->parent.byte;
359 }
360
361 /**
362  * gst_byte_writer_ensure_free_space:
363  * @writer: #GstByteWriter instance
364  * @size: Number of bytes that should be available
365  *
366  * Checks if enough free space from the current write cursor is
367  * available and reallocates if necessary.
368  *
369  * Returns: %TRUE if at least @size bytes are still available
370  *
371  * Since: 0.10.26
372  */
373 gboolean
374 gst_byte_writer_ensure_free_space (GstByteWriter * writer, guint size)
375 {
376   return _gst_byte_writer_ensure_free_space_inline (writer, size);
377 }
378
379
380 #define CREATE_WRITE_FUNC(bits,type,name,write_func) \
381 gboolean \
382 gst_byte_writer_put_##name (GstByteWriter *writer, type val) \
383 { \
384   return _gst_byte_writer_put_##name##_inline (writer, val); \
385 }
386
387 CREATE_WRITE_FUNC (8, guint8, uint8, GST_WRITE_UINT8);
388 CREATE_WRITE_FUNC (8, gint8, int8, GST_WRITE_UINT8);
389 CREATE_WRITE_FUNC (16, guint16, uint16_le, GST_WRITE_UINT16_LE);
390 CREATE_WRITE_FUNC (16, guint16, uint16_be, GST_WRITE_UINT16_BE);
391 CREATE_WRITE_FUNC (16, gint16, int16_le, GST_WRITE_UINT16_LE);
392 CREATE_WRITE_FUNC (16, gint16, int16_be, GST_WRITE_UINT16_BE);
393 CREATE_WRITE_FUNC (24, guint32, uint24_le, GST_WRITE_UINT24_LE);
394 CREATE_WRITE_FUNC (24, guint32, uint24_be, GST_WRITE_UINT24_BE);
395 CREATE_WRITE_FUNC (24, gint32, int24_le, GST_WRITE_UINT24_LE);
396 CREATE_WRITE_FUNC (24, gint32, int24_be, GST_WRITE_UINT24_BE);
397 CREATE_WRITE_FUNC (32, guint32, uint32_le, GST_WRITE_UINT32_LE);
398 CREATE_WRITE_FUNC (32, guint32, uint32_be, GST_WRITE_UINT32_BE);
399 CREATE_WRITE_FUNC (32, gint32, int32_le, GST_WRITE_UINT32_LE);
400 CREATE_WRITE_FUNC (32, gint32, int32_be, GST_WRITE_UINT32_BE);
401 CREATE_WRITE_FUNC (64, guint64, uint64_le, GST_WRITE_UINT64_LE);
402 CREATE_WRITE_FUNC (64, guint64, uint64_be, GST_WRITE_UINT64_BE);
403 CREATE_WRITE_FUNC (64, gint64, int64_le, GST_WRITE_UINT64_LE);
404 CREATE_WRITE_FUNC (64, gint64, int64_be, GST_WRITE_UINT64_BE);
405
406 CREATE_WRITE_FUNC (32, gfloat, float32_be, GST_WRITE_FLOAT_BE);
407 CREATE_WRITE_FUNC (32, gfloat, float32_le, GST_WRITE_FLOAT_LE);
408 CREATE_WRITE_FUNC (64, gdouble, float64_be, GST_WRITE_DOUBLE_BE);
409 CREATE_WRITE_FUNC (64, gdouble, float64_le, GST_WRITE_DOUBLE_LE);
410
411 gboolean
412 gst_byte_writer_put_data (GstByteWriter * writer, const guint8 * data,
413     guint size)
414 {
415   return _gst_byte_writer_put_data_inline (writer, data, size);
416 }
417
418 gboolean
419 gst_byte_writer_fill (GstByteWriter * writer, guint8 value, guint size)
420 {
421   return _gst_byte_writer_fill_inline (writer, value, size);
422 }
423
424 #define CREATE_WRITE_STRING_FUNC(bits,type) \
425 gboolean \
426 gst_byte_writer_put_string_utf##bits (GstByteWriter *writer, const type * data) \
427 { \
428   guint size = 0; \
429   \
430   g_return_val_if_fail (writer != NULL, FALSE); \
431   \
432   /* endianness does not matter if we are looking for a NUL terminator */ \
433   while (data[size] != 0) { \
434     /* have prevent overflow */ \
435     if (G_UNLIKELY (size == G_MAXUINT)) \
436       return FALSE; \
437     ++size; \
438   } \
439   ++size; \
440   \
441   if (G_UNLIKELY (!_gst_byte_writer_ensure_free_space_inline(writer, size * (bits / 8)))) \
442     return FALSE; \
443   \
444   _gst_byte_writer_put_data_inline (writer, (const guint8 *) data, size * (bits / 8)); \
445   \
446   return TRUE; \
447 }
448
449 CREATE_WRITE_STRING_FUNC (8, gchar);
450 CREATE_WRITE_STRING_FUNC (16, guint16);
451 CREATE_WRITE_STRING_FUNC (32, guint32);
452 /**
453  * gst_byte_writer_put_uint8:
454  * @writer: #GstByteWriter instance
455  * @val: Value to write
456  *
457  * Writes a unsigned 8 bit integer to @writer.
458  *
459  * Returns: %TRUE if the value could be written
460  *
461  * Since: 0.10.26
462  */
463 /**
464  * gst_byte_writer_put_uint16_be:
465  * @writer: #GstByteWriter instance
466  * @val: Value to write
467  *
468  * Writes a unsigned big endian 16 bit integer to @writer.
469  *
470  * Returns: %TRUE if the value could be written
471  *
472  * Since: 0.10.26
473  */
474 /**
475  * gst_byte_writer_put_uint24_be:
476  * @writer: #GstByteWriter instance
477  * @val: Value to write
478  *
479  * Writes a unsigned big endian 24 bit integer to @writer.
480  *
481  * Returns: %TRUE if the value could be written
482  *
483  * Since: 0.10.26
484  */
485 /**
486  * gst_byte_writer_put_uint32_be:
487  * @writer: #GstByteWriter instance
488  * @val: Value to write
489  *
490  * Writes a unsigned big endian 32 bit integer to @writer.
491  *
492  * Returns: %TRUE if the value could be written
493  *
494  * Since: 0.10.26
495  */
496 /**
497  * gst_byte_writer_put_uint64_be:
498  * @writer: #GstByteWriter instance
499  * @val: Value to write
500  *
501  * Writes a unsigned big endian 64 bit integer to @writer.
502  *
503  * Returns: %TRUE if the value could be written
504  *
505  * Since: 0.10.26
506  */
507 /**
508  * gst_byte_writer_put_uint16_le:
509  * @writer: #GstByteWriter instance
510  * @val: Value to write
511  *
512  * Writes a unsigned little endian 16 bit integer to @writer.
513  *
514  * Returns: %TRUE if the value could be written
515  *
516  * Since: 0.10.26
517  */
518 /**
519  * gst_byte_writer_put_uint24_le:
520  * @writer: #GstByteWriter instance
521  * @val: Value to write
522  *
523  * Writes a unsigned little endian 24 bit integer to @writer.
524  *
525  * Returns: %TRUE if the value could be written
526  *
527  * Since: 0.10.26
528  */
529 /**
530  * gst_byte_writer_put_uint32_le:
531  * @writer: #GstByteWriter instance
532  * @val: Value to write
533  *
534  * Writes a unsigned little endian 32 bit integer to @writer.
535  *
536  * Returns: %TRUE if the value could be written
537  *
538  * Since: 0.10.26
539  */
540 /**
541  * gst_byte_writer_put_uint64_le:
542  * @writer: #GstByteWriter instance
543  * @val: Value to write
544  *
545  * Writes a unsigned little endian 64 bit integer to @writer.
546  *
547  * Returns: %TRUE if the value could be written
548  *
549  * Since: 0.10.26
550  */
551 /**
552  * gst_byte_writer_put_int8:
553  * @writer: #GstByteWriter instance
554  * @val: Value to write
555  *
556  * Writes a signed 8 bit integer to @writer.
557  *
558  * Returns: %TRUE if the value could be written
559  *
560  * Since: 0.10.26
561  */
562 /**
563  * gst_byte_writer_put_int16_be:
564  * @writer: #GstByteWriter instance
565  * @val: Value to write
566  *
567  * Writes a signed big endian 16 bit integer to @writer.
568  *
569  * Returns: %TRUE if the value could be written
570  *
571  * Since: 0.10.26
572  */
573 /**
574  * gst_byte_writer_put_int24_be:
575  * @writer: #GstByteWriter instance
576  * @val: Value to write
577  *
578  * Writes a signed big endian 24 bit integer to @writer.
579  *
580  * Returns: %TRUE if the value could be written
581  *
582  * Since: 0.10.26
583  */
584 /**
585  * gst_byte_writer_put_int32_be:
586  * @writer: #GstByteWriter instance
587  * @val: Value to write
588  *
589  * Writes a signed big endian 32 bit integer to @writer.
590  *
591  * Returns: %TRUE if the value could be written
592  *
593  * Since: 0.10.26
594  */
595 /**
596  * gst_byte_writer_put_int64_be:
597  * @writer: #GstByteWriter instance
598  * @val: Value to write
599  *
600  * Writes a signed big endian 64 bit integer to @writer.
601  *
602  * Returns: %TRUE if the value could be written
603  *
604  * Since: 0.10.26
605  */
606 /**
607  * gst_byte_writer_put_int16_le:
608  * @writer: #GstByteWriter instance
609  * @val: Value to write
610  *
611  * Writes a signed little endian 16 bit integer to @writer.
612  *
613  * Returns: %TRUE if the value could be written
614  *
615  * Since: 0.10.26
616  */
617 /**
618  * gst_byte_writer_put_int24_le:
619  * @writer: #GstByteWriter instance
620  * @val: Value to write
621  *
622  * Writes a signed little endian 24 bit integer to @writer.
623  *
624  * Returns: %TRUE if the value could be written
625  *
626  * Since: 0.10.26
627  */
628 /**
629  * gst_byte_writer_put_int32_le:
630  * @writer: #GstByteWriter instance
631  * @val: Value to write
632  *
633  * Writes a signed little endian 32 bit integer to @writer.
634  *
635  * Returns: %TRUE if the value could be written
636  *
637  * Since: 0.10.26
638  */
639 /**
640  * gst_byte_writer_put_int64_le:
641  * @writer: #GstByteWriter instance
642  * @val: Value to write
643  *
644  * Writes a signed little endian 64 bit integer to @writer.
645  *
646  * Returns: %TRUE if the value could be written
647  *
648  * Since: 0.10.26
649  */
650 /**
651  * gst_byte_writer_put_float32_be:
652  * @writer: #GstByteWriter instance
653  * @val: Value to write
654  *
655  * Writes a big endian 32 bit float to @writer.
656  *
657  * Returns: %TRUE if the value could be written
658  *
659  * Since: 0.10.27
660  */
661 /**
662  * gst_byte_writer_put_float64_be:
663  * @writer: #GstByteWriter instance
664  * @val: Value to write
665  *
666  * Writes a big endian 64 bit float to @writer.
667  *
668  * Returns: %TRUE if the value could be written
669  *
670  * Since: 0.10.27
671  */
672 /**
673  * gst_byte_writer_put_float32_le:
674  * @writer: #GstByteWriter instance
675  * @val: Value to write
676  *
677  * Writes a little endian 32 bit float to @writer.
678  *
679  * Returns: %TRUE if the value could be written
680  *
681  * Since: 0.10.27
682  */
683 /**
684  * gst_byte_writer_put_float64_le:
685  * @writer: #GstByteWriter instance
686  * @val: Value to write
687  *
688  * Writes a little endian 64 bit float to @writer.
689  *
690  * Returns: %TRUE if the value could be written
691  *
692  * Since: 0.10.27
693  */
694 /**
695  * gst_byte_writer_put_string_utf8:
696  * @writer: #GstByteWriter instance
697  * @data: (transfer none) (array zero-terminated=1) (type utf8): UTF8 string to
698  *     write
699  *
700  * Writes a NUL-terminated UTF8 string to @writer (including the terminator).
701  *
702  * Returns: %TRUE if the value could be written
703  *
704  * Since: 0.10.26
705  */
706 /**
707  * gst_byte_writer_put_string_utf16:
708  * @writer: #GstByteWriter instance
709  * @data: (transfer none) (array zero-terminated=1): UTF16 string to write
710  *
711  * Writes a NUL-terminated UTF16 string to @writer (including the terminator).
712  *
713  * Returns: %TRUE if the value could be written
714  *
715  * Since: 0.10.26
716  */
717 /**
718  * gst_byte_writer_put_string_utf32:
719  * @writer: #GstByteWriter instance
720  * @data: (transfer none) (array zero-terminated=1): UTF32 string to write
721  *
722  * Writes a NUL-terminated UTF32 string to @writer (including the terminator).
723  *
724  * Returns: %TRUE if the value could be written
725  *
726  * Since: 0.10.26
727  */
728 /**
729  * gst_byte_writer_put_data:
730  * @writer: #GstByteWriter instance
731  * @data: (transfer none) (array length=size): Data to write
732  * @size: Size of @data in bytes
733  *
734  * Writes @size bytes of @data to @writer.
735  *
736  * Returns: %TRUE if the value could be written
737  *
738  * Since: 0.10.26
739  */
740 /**
741  * gst_byte_writer_fill:
742  * @writer: #GstByteWriter instance
743  * @value: Value to be writen
744  * @size: Number of bytes to be writen
745  *
746  * Writes @size bytes containing @value to @writer.
747  *
748  * Returns: %TRUE if the value could be written
749  *
750  * Since: 0.10.27
751  */
752
753 /**
754  * gst_byte_writer_put_buffer:
755  * @writer: #GstByteWriter instance
756  * @buffer: (transfer none): source #GstBuffer
757  * @offset: offset to copy from
758  * @size: total size to copy. If -1, all data is copied
759  *
760  * Writes @size bytes of @data to @writer.
761  *
762  * Returns: %TRUE if the data could be written
763  *
764  */