add deug message
[swfdec.git] / libswfdec / swfdec_loader.c
blob9bde0572629ae9b713d49ab8ef59bf80ac1475c2
1 /* Swfdec
2 * Copyright (C) 2006-2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include <string.h>
25 #include "swfdec_loader_internal.h"
26 #include "swfdec_buffer.h"
27 #include "swfdec_debug.h"
28 #include "swfdec_loadertarget.h"
29 #include "swfdec_player_internal.h"
31 /*** gtk-doc ***/
33 /**
34 * SECTION:SwfdecLoader
35 * @title: SwfdecLoader
36 * @short_description: object used for input
38 * SwfdecLoader is the base class used for input. Since developers normally
39 * need to adapt input to the needs of their application, this class is
40 * provided to be adapted to their needs.
42 * Since Flash files can load new resources while operating, a #SwfdecLoader
43 * can be instructed to load another resource. It's the loader's responsibility
44 * to make sure the player is allowed to access the resource and provide its
45 * data.
47 * For convenience, a #SwfdecLoader for file access is provided by Swfdec.
50 /**
51 * SwfdecLoader:
53 * This is the base class used for providing input. It is abstract, use a
54 * subclass to provide your input.
57 /**
58 * SwfdecLoaderDataType:
59 * @SWFDEC_LOADER_DATA_UNKNOWN: Unidentified data or data that cannot be
60 * identified.
61 * @SWFDEC_LOADER_DATA_SWF: Data describing a normal Flash file.
62 * @SWFDEC_LOADER_DATA_FLV: Data describing a Flash video stream.
63 * @SWFDEC_LOADER_DATA_XML: Data in XML format.
64 * @SWFDEC_LOADER_DATA_TEXT: Textual data.
66 * This type describes the different types of data that can be loaded inside
67 * Swfdec. Swfdec identifies its data streams and you can use the
68 * swfdec_loader_get_data_type() to acquire more information about the data
69 * inside a #SwfdecLoader.
72 /**
73 * SwfdecLoaderRequest:
74 * @SWFDEC_LOADER_REQUEST_DEFAULT: Use the default method (this most likely is
75 * equal to HTTPget)
76 * @SWFDEC_LOADER_REQUEST_GET: Use HTTP get
77 * @SWFDEC_LOADER_REQUEST_POST: Use HTTP post
79 * Describes the moethod to use for requesting a given URL. These methods map
80 * naturally to HTTP methods, since HTTP is the common method for requesting
81 * Flash content.
84 /*** SwfdecLoader ***/
86 enum {
87 PROP_0,
88 PROP_ERROR,
89 PROP_EOF,
90 PROP_DATA_TYPE,
91 PROP_SIZE,
92 PROP_LOADED,
93 PROP_URL
96 G_DEFINE_ABSTRACT_TYPE (SwfdecLoader, swfdec_loader, G_TYPE_OBJECT)
98 static void
99 swfdec_loader_get_property (GObject *object, guint param_id, GValue *value,
100 GParamSpec * pspec)
102 SwfdecLoader *loader = SWFDEC_LOADER (object);
104 switch (param_id) {
105 case PROP_ERROR:
106 g_value_set_string (value, loader->error);
107 break;
108 case PROP_EOF:
109 g_value_set_boolean (value, loader->state == SWFDEC_LOADER_STATE_EOF);
110 break;
111 case PROP_DATA_TYPE:
112 g_value_set_enum (value, loader->data_type);
113 break;
114 case PROP_SIZE:
115 g_value_set_ulong (value, loader->size);
116 break;
117 case PROP_LOADED:
118 g_value_set_ulong (value, swfdec_loader_get_loaded (loader));
119 break;
120 case PROP_URL:
121 g_value_set_boxed (value, loader->url);
122 break;
123 default:
124 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
125 break;
129 static void
130 swfdec_loader_set_property (GObject *object, guint param_id, const GValue *value,
131 GParamSpec *pspec)
133 SwfdecLoader *loader = SWFDEC_LOADER (object);
135 switch (param_id) {
136 case PROP_ERROR:
137 swfdec_loader_error (loader, g_value_get_string (value));
138 break;
139 case PROP_SIZE:
140 if (loader->size == 0 && g_value_get_ulong (value) > 0)
141 swfdec_loader_set_size (loader, g_value_get_ulong (value));
142 break;
143 case PROP_URL:
144 loader->url = g_value_dup_boxed (value);
145 if (loader->url == NULL) {
146 g_warning ("must set a valid URL");
147 loader->url = swfdec_url_new ("");
149 break;
150 default:
151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
152 break;
156 static void
157 swfdec_loader_dispose (GObject *object)
159 SwfdecLoader *loader = SWFDEC_LOADER (object);
161 /* targets are supposed to keep a reference around */
162 g_assert (loader->target == NULL);
163 swfdec_buffer_queue_unref (loader->queue);
164 swfdec_url_free (loader->url);
165 g_free (loader->error);
167 G_OBJECT_CLASS (swfdec_loader_parent_class)->dispose (object);
170 static void
171 swfdec_loader_class_init (SwfdecLoaderClass *klass)
173 GObjectClass *object_class = G_OBJECT_CLASS (klass);
175 object_class->dispose = swfdec_loader_dispose;
176 object_class->get_property = swfdec_loader_get_property;
177 object_class->set_property = swfdec_loader_set_property;
179 g_object_class_install_property (object_class, PROP_ERROR,
180 g_param_spec_string ("error", "error", "NULL when no error or string describing error",
181 NULL, G_PARAM_READABLE));
182 g_object_class_install_property (object_class, PROP_EOF,
183 g_param_spec_boolean ("eof", "eof", "TRUE when all data has been handed to the loader",
184 FALSE, G_PARAM_READABLE));
185 g_object_class_install_property (object_class, PROP_DATA_TYPE,
186 g_param_spec_enum ("data-type", "data type", "the data's type as identified by Swfdec",
187 SWFDEC_TYPE_LOADER_DATA_TYPE, SWFDEC_LOADER_DATA_UNKNOWN, G_PARAM_READABLE));
188 g_object_class_install_property (object_class, PROP_SIZE,
189 g_param_spec_ulong ("size", "size", "amount of bytes in loader",
190 0, G_MAXULONG, 0, G_PARAM_READWRITE));
191 g_object_class_install_property (object_class, PROP_LOADED,
192 g_param_spec_ulong ("loaded", "loaded", "bytes already loaded",
193 0, G_MAXULONG, 0, G_PARAM_READWRITE));
194 g_object_class_install_property (object_class, PROP_URL,
195 g_param_spec_boxed ("url", "url", "URL for this file",
196 SWFDEC_TYPE_URL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
199 static void
200 swfdec_loader_init (SwfdecLoader *loader)
202 loader->queue = swfdec_buffer_queue_new ();
203 loader->data_type = SWFDEC_LOADER_DATA_UNKNOWN;
206 /*** INTERNAL API ***/
208 static void
209 swfdec_loader_perform_open (gpointer loaderp, gpointer unused)
211 SwfdecLoader *loader = loaderp;
213 swfdec_loader_target_open (loader->target, loader);
216 static void
217 swfdec_loader_perform_eof (gpointer loaderp, gpointer unused)
219 SwfdecLoader *loader = loaderp;
221 swfdec_loader_target_eof (loader->target, loader);
224 static void
225 swfdec_loader_perform_error (gpointer loaderp, gpointer unused)
227 SwfdecLoader *loader = loaderp;
229 swfdec_loader_target_error (loader->target, loader);
232 static void
233 swfdec_loader_perform_push (gpointer loaderp, gpointer unused)
235 SwfdecLoader *loader = loaderp;
237 swfdec_loader_target_parse (loader->target, loader);
240 SwfdecLoader *
241 swfdec_loader_load (SwfdecLoader *loader, const char *url_string,
242 SwfdecLoaderRequest request, const char *data, gsize data_len)
244 SwfdecLoader *ret;
245 SwfdecLoaderClass *klass;
246 SwfdecURL *url;
248 g_return_val_if_fail (SWFDEC_IS_LOADER (loader), NULL);
249 g_return_val_if_fail (url_string != NULL, NULL);
250 g_return_val_if_fail (data != NULL || data_len == 0, NULL);
252 klass = SWFDEC_LOADER_GET_CLASS (loader);
253 g_return_val_if_fail (klass->load != NULL, NULL);
254 url = swfdec_url_new_relative (loader->url, url_string);
255 ret = g_object_new (G_OBJECT_CLASS_TYPE (klass), "url", url, NULL);
256 swfdec_url_free (url);
257 klass->load (ret, loader, request, data, data_len);
258 return ret;
261 void
262 swfdec_loader_close (SwfdecLoader *loader)
264 SwfdecLoaderClass *klass;
266 g_return_if_fail (SWFDEC_IS_LOADER (loader));
267 klass = SWFDEC_LOADER_GET_CLASS (loader);
269 if (klass->close)
270 klass->close (loader);
271 if (loader->state != SWFDEC_LOADER_STATE_ERROR)
272 loader->state = SWFDEC_LOADER_STATE_CLOSED;
275 void
276 swfdec_loader_set_target (SwfdecLoader *loader, SwfdecLoaderTarget *target)
278 g_return_if_fail (SWFDEC_IS_LOADER (loader));
279 g_return_if_fail (target == NULL || SWFDEC_IS_LOADER_TARGET (target));
281 if (loader->target) {
282 swfdec_player_remove_all_external_actions (loader->player, loader);
284 loader->target = target;
285 if (target) {
286 loader->player = swfdec_loader_target_get_player (target);
287 switch (loader->state) {
288 case SWFDEC_LOADER_STATE_NEW:
289 break;
290 case SWFDEC_LOADER_STATE_OPEN:
291 swfdec_player_add_external_action (loader->player, loader,
292 swfdec_loader_perform_open, NULL);
293 break;
294 case SWFDEC_LOADER_STATE_READING:
295 swfdec_player_add_external_action (loader->player, loader,
296 swfdec_loader_perform_open, NULL);
297 swfdec_player_add_external_action (loader->player, loader,
298 swfdec_loader_perform_push, NULL);
299 break;
300 case SWFDEC_LOADER_STATE_EOF:
301 swfdec_player_add_external_action (loader->player, loader,
302 swfdec_loader_perform_open, NULL);
303 swfdec_player_add_external_action (loader->player, loader,
304 swfdec_loader_perform_push, NULL);
305 swfdec_player_add_external_action (loader->player, loader,
306 swfdec_loader_perform_eof, NULL);
307 break;
308 case SWFDEC_LOADER_STATE_ERROR:
309 swfdec_player_add_external_action (loader->player, loader,
310 swfdec_loader_perform_error, NULL);
311 break;
312 default:
313 g_assert_not_reached ();
314 break;
316 } else {
317 loader->player = NULL;
321 /** PUBLIC API ***/
324 * swfdec_loader_error:
325 * @loader: a #SwfdecLoader
326 * @error: a string describing the error
328 * Moves the loader in the error state if it wasn't before. A loader that is in
329 * the error state will not process any more data. Also, internal error
330 * handling scripts may be executed.
332 void
333 swfdec_loader_error (SwfdecLoader *loader, const char *error)
335 g_return_if_fail (SWFDEC_IS_LOADER (loader));
336 g_return_if_fail (error != NULL);
338 if (loader->error) {
339 SWFDEC_ERROR ("another error in loader %p: %s", loader, error);
340 return;
343 SWFDEC_ERROR ("error in loader %p: %s", loader, error);
344 loader->state = SWFDEC_LOADER_STATE_ERROR;
345 loader->error = g_strdup (error);
346 if (loader->target)
347 swfdec_player_add_external_action (loader->player, loader,
348 swfdec_loader_perform_error, NULL);
352 * swfdec_loader_open:
353 * @loader: a #SwfdecLoader
354 * @url: the real URL used for this loader if it has changed (e.g. after HTTP
355 * redirects) or %NULL if it hasn't changed
357 * Call this function when your loader opened the resulting file. For HTTP this
358 * is when having received the headers. You must call this function before
359 * swfdec_laoder_push() can be called.
361 void
362 swfdec_loader_open (SwfdecLoader *loader, const char *url)
364 g_return_if_fail (SWFDEC_IS_LOADER (loader));
365 g_return_if_fail (loader->state == SWFDEC_LOADER_STATE_NEW);
367 loader->state = SWFDEC_LOADER_STATE_OPEN;
368 if (url) {
369 swfdec_url_free (loader->url);
370 loader->url = swfdec_url_new (url);
371 g_object_notify (G_OBJECT (loader), "url");
373 if (loader->player)
374 swfdec_player_add_external_action (loader->player, loader, swfdec_loader_perform_open, NULL);
378 * swfdec_loader_push:
379 * @loader: a #SwfdecLoader
380 * @buffer: new data to make available. The loader takes the reference
381 * to the buffer.
383 * Makes the data in @buffer available to @loader and processes it. The @loader
384 * must be open.
386 void
387 swfdec_loader_push (SwfdecLoader *loader, SwfdecBuffer *buffer)
389 g_return_if_fail (SWFDEC_IS_LOADER (loader));
390 g_return_if_fail (loader->state == SWFDEC_LOADER_STATE_OPEN || loader->state == SWFDEC_LOADER_STATE_READING);
391 g_return_if_fail (buffer != NULL);
393 swfdec_buffer_queue_push (loader->queue, buffer);
394 g_object_notify (G_OBJECT (loader), "loaded");
395 loader->state = SWFDEC_LOADER_STATE_READING;
396 if (loader->player)
397 swfdec_player_add_external_action (loader->player, loader,
398 swfdec_loader_perform_push, NULL);
402 * swfdec_loader_eof:
403 * @loader: a #SwfdecLoader
405 * Indicates to @loader that no more data will follow. The loader must be open.
407 void
408 swfdec_loader_eof (SwfdecLoader *loader)
410 g_return_if_fail (SWFDEC_IS_LOADER (loader));
411 g_return_if_fail (loader->state == SWFDEC_LOADER_STATE_OPEN || loader->state == SWFDEC_LOADER_STATE_READING);
413 if (loader->size == 0) {
414 gulong bytes = swfdec_loader_get_loaded (loader);
415 if (bytes)
416 swfdec_loader_set_size (loader, bytes);
418 g_object_notify (G_OBJECT (loader), "eof");
419 loader->state = SWFDEC_LOADER_STATE_EOF;
420 if (loader->player)
421 swfdec_player_add_external_action (loader->player, loader,
422 swfdec_loader_perform_eof, NULL);
426 * swfdec_loader_get_filename:
427 * @loader: a #SwfdecLoader
429 * Gets the suggested filename to use for this loader. This may be of interest
430 * when displaying information about the file that is played back.
432 * Returns: A string in the glib filename encoding that contains the filename
433 * for this loader. g_free() after use.
435 char *
436 swfdec_loader_get_filename (SwfdecLoader *loader)
438 const SwfdecURL *url;
439 const char *path, *ext;
440 char *ret = NULL;
442 g_return_val_if_fail (SWFDEC_IS_LOADER (loader), NULL);
444 url = swfdec_loader_get_url (loader);
445 path = swfdec_url_get_path (url);
446 if (path) {
447 char *s = strrchr (path, '/');
448 if (s)
449 path = s + 1;
450 if (path[0] == 0)
451 path = NULL;
453 if (path)
454 ret = g_filename_from_utf8 (path, -1, NULL, NULL, NULL);
455 if (ret == NULL)
456 ret = g_strdup ("unknown");
458 ext = swfdec_loader_data_type_get_extension (loader->data_type);
459 if (*ext) {
460 char *dot = strrchr (ret, '.');
461 char *real;
462 guint len = dot ? strlen (dot) : G_MAXUINT;
463 if (len <= 5)
464 *dot = '\0';
465 real = g_strdup_printf ("%s.%s", ret, ext);
466 g_free (ret);
467 ret = real;
470 return ret;
474 * swfdec_loader_get_url:
475 * @loader: a #SwfdecLoader
477 * Gets the url this loader is handling. This is mostly useful for writing
478 * subclasses of #SwfdecLoader.
480 * Returns: a #SwfdecURL describing @loader.
482 const SwfdecURL *
483 swfdec_loader_get_url (SwfdecLoader *loader)
485 g_return_val_if_fail (SWFDEC_IS_LOADER (loader), NULL);
487 return loader->url;
491 * swfdec_loader_get_data_type:
492 * @loader: a #SwfdecLoader
494 * Queries the type of data this loader provides. The type is determined
495 * automatically by Swfdec.
497 * Returns: the type this data was identified to be in or
498 * #SWFDEC_LOADER_DATA_UNKNOWN if not identified
500 SwfdecLoaderDataType
501 swfdec_loader_get_data_type (SwfdecLoader *loader)
503 g_return_val_if_fail (SWFDEC_IS_LOADER (loader), SWFDEC_LOADER_DATA_UNKNOWN);
505 return loader->data_type;
508 void
509 swfdec_loader_set_data_type (SwfdecLoader *loader, SwfdecLoaderDataType type)
511 g_return_if_fail (SWFDEC_IS_LOADER (loader));
512 g_return_if_fail (loader->data_type == SWFDEC_LOADER_DATA_UNKNOWN);
513 g_return_if_fail (type != SWFDEC_LOADER_DATA_UNKNOWN);
515 loader->data_type = type;
516 g_object_notify (G_OBJECT (loader), "data-type");
520 * swfdec_loader_set_size:
521 * @loader: a #SwfdecLoader
522 * @size: the amount of bytes in this loader
524 * Sets the size of bytes in this loader. This function may only be called once.
526 void
527 swfdec_loader_set_size (SwfdecLoader *loader, gulong size)
529 g_return_if_fail (SWFDEC_IS_LOADER (loader));
530 g_return_if_fail (loader->size == 0);
531 g_return_if_fail (size > 0);
533 loader->size = size;
534 g_object_notify (G_OBJECT (loader), "size");
538 * swfdec_loader_get_size:
539 * @loader: a #SwfdecLoader
541 * Queries the amount of bytes inside @loader. If the size is unknown, 0 is
542 * returned.
544 * Returns: the total number of bytes for this loader or 0 if unknown
546 gulong
547 swfdec_loader_get_size (SwfdecLoader *loader)
549 g_return_val_if_fail (SWFDEC_IS_LOADER (loader), 0);
551 return loader->size;
555 * swfdec_loader_get_loaded:
556 * @loader: a #SwfdecLoader
558 * Gets the amount of bytes that have already been pushed into @loader and are
559 * available to Swfdec.
561 * Returns: Amount of bytes in @loader
563 gulong
564 swfdec_loader_get_loaded (SwfdecLoader *loader)
566 g_return_val_if_fail (SWFDEC_IS_LOADER (loader), 0);
568 return swfdec_buffer_queue_get_depth (loader->queue) +
569 swfdec_buffer_queue_get_offset (loader->queue);
573 * swfdec_loader_data_type_get_extension:
574 * @type: a #SwfdecLoaderDataType
576 * Queries the extension to be used for data of the given @type.
578 * Returns: the typical extension for this data type or the empty string
579 * if the type has no extension
581 const char *
582 swfdec_loader_data_type_get_extension (SwfdecLoaderDataType type)
584 switch (type) {
585 case SWFDEC_LOADER_DATA_UNKNOWN:
586 return "";
587 case SWFDEC_LOADER_DATA_SWF:
588 return "swf";
589 case SWFDEC_LOADER_DATA_FLV:
590 return "flv";
591 case SWFDEC_LOADER_DATA_XML:
592 return "xml";
593 case SWFDEC_LOADER_DATA_TEXT:
594 return "txt";
595 default:
596 g_warning ("unknown data type %u", type);
597 return "";
601 /*** X-WWW-FORM-URLENCODED ***/
603 /* if speed ever gets an issue, use a 256 byte array instead of strchr */
604 static const char *urlencode_unescaped="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.,:/()'";
605 static void
606 swfdec_urlencode_append_string (GString *str, const char *s)
608 g_assert (s != NULL);
609 while (*s) {
610 if (strchr (urlencode_unescaped, *s))
611 g_string_append_c (str, *s);
612 else if (*s == ' ')
613 g_string_append_c (str, '+');
614 else
615 g_string_append_printf (str, "%%%02X", (guint) *s);
616 s++;
620 static char *
621 swfdec_urldecode_one_string (const char *s, const char **out)
623 GString *ret = g_string_new ("");
625 while (*s) {
626 if (strchr (urlencode_unescaped, *s)) {
627 g_string_append_c (ret, *s);
628 } else if (*s == '+') {
629 g_string_append_c (ret, ' ');
630 } else if (*s == '%') {
631 guint byte;
632 s++;
633 if (*s >= '0' && *s <= '9') {
634 byte = *s - '0';
635 } else if (*s >= 'A' && *s <= 'F') {
636 byte = *s - 'A' + 10;
637 } else if (*s >= 'a' && *s <= 'f') {
638 byte = *s - 'a' + 10;
639 } else {
640 g_string_free (ret, TRUE);
641 *out = s;
642 return NULL;
644 byte *= 16;
645 s++;
646 if (*s >= '0' && *s <= '9') {
647 byte += *s - '0';
648 } else if (*s >= 'A' && *s <= 'F') {
649 byte += *s - 'A' + 10;
650 } else if (*s >= 'a' && *s <= 'f') {
651 byte += *s - 'a' + 10;
652 } else {
653 g_string_free (ret, TRUE);
654 *out = s;
655 return NULL;
657 g_assert (byte < 256);
658 g_string_append_c (ret, byte);
659 } else {
660 break;
662 s++;
664 *out = s;
665 return g_string_free (ret, FALSE);
669 * swfdec_string_append_urlencoded:
670 * @str: a #GString
671 * @name: name of the property to append
672 * @value: value of property to append or NULL for empty
674 * Appends a name/value pair in encoded as 'application/x-www-form-urlencoded'
675 * to the given @str
677 void
678 swfdec_string_append_urlencoded (GString *str, const char *name, const char *value)
680 g_return_if_fail (str != NULL);
681 g_return_if_fail (name != NULL);
683 if (str->len > 0)
684 g_string_append_c (str, '&');
685 swfdec_urlencode_append_string (str, name);
686 g_string_append_c (str, '=');
687 if (value)
688 swfdec_urlencode_append_string (str, value);
692 * swfdec_urldecode_one:
693 * @string: string in 'application/x-www-form-urlencoded' form
694 * @name: pointer that will hold a newly allocated string for the name of the
695 * parsed property or NULL
696 * @value: pointer that will hold a newly allocated string containing the
697 * value of the parsed property or NULL
698 * @end: If not %NULL, on success, pointer to the first byte in @s that was
699 * not parsed. On failure it will point to the byte causing the problem
701 * Tries to parse the given @string into a name/value pair, assuming the string
702 * is in the application/x-www-form-urlencoded format. If the parsing succeeds,
703 * @name and @value will contain the parsed values and %TRUE will be returned.
705 * Returns: %TRUE if parsing the property succeeded, %FALSE otherwise
707 gboolean
708 swfdec_urldecode_one (const char *string, char **name, char **value, const char **end)
710 char *name_str, *value_str;
712 g_return_val_if_fail (string != NULL, FALSE);
714 name_str = swfdec_urldecode_one_string (string, &string);
715 if (name_str == NULL)
716 goto fail;
717 if (*string != '=') {
718 g_free (name_str);
719 goto fail;
721 string++;
722 value_str = swfdec_urldecode_one_string (string, &string);
723 if (value_str == NULL) {
724 g_free (name_str);
725 goto fail;
728 if (name)
729 *name = name_str;
730 else
731 g_free (name_str);
732 if (value)
733 *value = value_str;
734 else
735 g_free (value_str);
736 if (end)
737 *end = string;
738 return TRUE;
740 fail:
741 if (name)
742 *name = NULL;
743 if (value)
744 *value = NULL;
745 if (end)
746 *end = string;
747 return FALSE;