Annotation of gpl/axl/src/axl_stream.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  *  LibAxl:  Another XML library
        !             3:  *  Copyright (C) 2006 Advanced Software Production Line, S.L.
        !             4:  *
        !             5:  *  This program is free software; you can redistribute it and/or
        !             6:  *  modify it under the terms of the GNU Lesser General Public License
        !             7:  *  as published by the Free Software Foundation; either version 2.1 of
        !             8:  *  the License, or (at your option) any later version.
        !             9:  *
        !            10:  *  This program 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  
        !            13:  *  GNU Lesser General Public License for more details.
        !            14:  *
        !            15:  *  You should have received a copy of the GNU Lesser General Public
        !            16:  *  License along with this program; if not, write to the Free
        !            17:  *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
        !            18:  *  02111-1307 USA
        !            19:  *  
        !            20:  *  You may find a copy of the license under this software is released
        !            21:  *  at COPYING file. This is LGPL software: you are welcome to
        !            22:  *  develop proprietary applications using this library without any
        !            23:  *  royalty or fee but returning back any change, improvement or
        !            24:  *  addition in the form of source code, project image, documentation
        !            25:  *  patches, etc. 
        !            26:  *
        !            27:  *  For commercial support on build XML enabled solutions contact us:
        !            28:  *          
        !            29:  *      Postal address:
        !            30:  *         Advanced Software Production Line, S.L.
        !            31:  *         Edificio Alius A, Oficina 102,
        !            32:  *         C/ Antonio Suarez Nº 10,
        !            33:  *         Alcalá de Henares 28802 Madrid
        !            34:  *         Spain
        !            35:  *
        !            36:  *      Email address:
        !            37:  *         info@aspl.es - http://www.aspl.es/xml
        !            38:  */
        !            39: 
        !            40: #include <axl.h>
        !            41: #include <math.h>
        !            42: 
        !            43: #define LOG_DOMAIN "axl-stream"
        !            44: 
        !            45: /** 
        !            46:  * @internal
        !            47:  *
        !            48:  * @brief Basic checking which allows to test if the provided size
        !            49:  * could be satisfied by the current status of the provided stream.
        !            50:  * 
        !            51:  * @param stream The stream where the operation will be performed.
        !            52:  *
        !            53:  * @param size The size to check.
        !            54:  * 
        !            55:  * @return 1 if the size falls out side the stream limit or 0 it not.
        !            56:  */
        !            57: #define fall_out_side_checking(stream, size) ((size + stream->stream_index) > stream->stream_size)
        !            58: 
        !            59: /** 
        !            60:  * @internal
        !            61:  * 
        !            62:  * This is the size of the buffer allocated while using the axlStream
        !            63:  * as a representation of a streaming media, like a file
        !            64:  * descriptor. This value should contain a value using the (4k * n + 1).
        !            65:  * 
        !            66:  * @param stream 
        !            67:  */
        !            68: #define STREAM_BUFFER_SIZE 8192
        !            69: 
        !            70: /** 
        !            71:  * @internal
        !            72:  *
        !            73:  * Internal definition used to represent the maximum value used for
        !            74:  * calls done to match a set of chunks. 
        !            75:  */
        !            76: #define MAX_INSPECTED_CHUNKS 30
        !            77: 
        !            78: typedef  enum {
        !            79:        STREAM_FD,
        !            80:        STREAM_MEM
        !            81: }axlStreamType;
        !            82: 
        !            83: struct _axlStream {
        !            84: 
        !            85:        /* current stream content */
        !            86:        char * stream;
        !            87: 
        !            88:        /* where the current stream is positioned. */
        !            89:        int    stream_index;
        !            90: 
        !            91:        /* global index for the device being streamed */
        !            92:        int    global_index;
        !            93: 
        !            94:        /* current stream size */
        !            95:        int    stream_size;
        !            96: 
        !            97:        /* stream buffer size (maximum amount of bytes to hold, used
        !            98:         * also to measure the temporal buffer) */
        !            99:        int    buffer_size;
        !           100:        
        !           101:        /* previous inspected stream size */
        !           102:        int    previous_inspect;
        !           103: 
        !           104:        /* last chunk get from the stream */
        !           105:        char   * last_chunk;
        !           106:        
        !           107:        /* last near to reference. */
        !           108:        char   * last_near_to;
        !           109: 
        !           110:        /* last get following reference */
        !           111:        char   * last_get_following;
        !           112: 
        !           113:        /* support variable for chunk matching */
        !           114:        char  ** chunks;
        !           115: 
        !           116:        /* support variable for chunk matching */
        !           117:        int   * lengths;
        !           118: 
        !           119:        /* a reference to the associated element to this stream */
        !           120:        axlList * elements_linked;
        !           121:        
        !           122:        /*The function to execute when the element must be destroyed. */ 
        !           123:        axlDestroyFunc element_destroy;
        !           124: 
        !           125:        /* Stream type configuration. Information source is coming
        !           126:         * from a file descriptor of a memory address. */
        !           127:        axlStreamType type;
        !           128: 
        !           129:        /* File descriptor associated with the given stream. In the
        !           130:         * case the stream if a STREAM_FD, this is the file descriptor
        !           131:         * associated. */
        !           132:        int           fd;
        !           133: 
        !           134:        /* Temporal buffer used by the stream to handle prebuffering
        !           135:         * operations.
        !           136:         */
        !           137:        char      * temp;
        !           138:        char      * decode_temp;
        !           139:        int         decode_temp_size;
        !           140:        int         decode_temp_index;
        !           141:        int         decode_temp_last;
        !           142:        int         decode_temp_remain;
        !           143:        char      * source_encoding;
        !           144: 
        !           145:        /* here is how these variables are used to decode content:
        !           146:         * 
        !           147:         * [   <---  decode_temp buffer ---> ] <- decode_temp_size: total buffer size (bytes)
        !           148:         *   ^                ^
        !           149:         *   |                |     
        !           150:         *   |                +-- decode_temp_last: last valid content in the buffer (bytes)
        !           151:         *   +-- decode_temp_index: next content to be consumed (bytes)
        !           152:         *
        !           153:         * [decode_temp_remain]: is the amount of content pending to
        !           154:         * be decoded. That is, starting from decode_temp_remain until
        !           155:         * last is the valid content still to be decoded.
        !           156:         *
        !           157:         * [source_encoding]: is defined to hold the value of the
        !           158:         * format for the source.
        !           159:         */
        !           160: 
        !           161:        /* more variables used to perform work: at get until */
        !           162:        char      * valid_chars;
        !           163:        int         chunk_matched;
        !           164:        axl_bool    accept_terminator;
        !           165:        int         result_size;
        !           166:        int         chunk_num;
        !           167: 
        !           168:        /** 
        !           169:         * @internal Internal variable used to notify get_until
        !           170:         * function that the last 0 character for stream memory
        !           171:         * operation done in a STREAM_MEM must be considered as a
        !           172:         * terminator character found.
        !           173:         */
        !           174:        axl_bool        zero;
        !           175: 
        !           176:        /** 
        !           177:         * @internal Alloc function to be used to require memory for
        !           178:         * chunks to be returned. This is used by Axl Stream to allow
        !           179:         * external modules to handle how memory is allocated while
        !           180:         * calling to axl_stream_get_until* API. 
        !           181:         *
        !           182:         * Currently, it is used by the axl_doc module to allocate axl
        !           183:         * stream using a string factory.
        !           184:         */
        !           185:        axlStreamAlloc alloc;
        !           186:        
        !           187:        /** 
        !           188:         * @internal User defined data to be passed to the alloc
        !           189:         * function.
        !           190:         */
        !           191:        axlPointer     alloc_data;
        !           192: 
        !           193:        /** 
        !           194:         * @internal Function used by the stream to decode content
        !           195:         * into utf-8. This is not used in all cases.
        !           196:         */
        !           197:        axlStreamDecode decode_f;
        !           198:        
        !           199:        /** 
        !           200:         * @internal Reference to user defined pointer provided to the
        !           201:         * decode_f function.
        !           202:         */
        !           203:        axlPointer      decode_f_data;
        !           204: 
        !           205:        /** 
        !           206:         * @internal Value that allows to signal that the buffer needs
        !           207:         * to be expanded (no matter what shows current indexes).
        !           208:         */
        !           209:        axl_bool        needs_expansion;
        !           210: 
        !           211:        /** 
        !           212:         * @internal Reference to the content check function
        !           213:         * installed.
        !           214:         */
        !           215:        axlStreamContentCheck check_f;
        !           216: 
        !           217:        /** 
        !           218:         * @internal Reference to user defined pointer to be passed to
        !           219:         * the content check function (check_f).
        !           220:         */
        !           221:        axlPointer            check_f_data;
        !           222: };
        !           223: 
        !           224: 
        !           225: /**
        !           226:  * \defgroup axl_stream_module Axl Stream Document: Abstract stream where a xml document is expected (also provided string functions)
        !           227:  */
        !           228: 
        !           229: /** 
        !           230:  * \addtogroup axl_stream_module
        !           231:  * @{
        !           232:  */
        !           233: 
        !           234: /** 
        !           235:  * @internal
        !           236:  *
        !           237:  * @brief Read the next available information on the file descriptor
        !           238:  * placing that information into the stream.
        !           239:  * 
        !           240:  * @param stream The stream where the pre-buffering operation will be
        !           241:  * performed.
        !           242:  *
        !           243:  * @param appended_content New content to be included at the begining
        !           244:  * of the stream while doing the prebuffer operation. This value could
        !           245:  * be null.
        !           246:  *
        !           247:  * @param appended_size The size for the appended content to be added.
        !           248:  * 
        !           249:  * @return \ref axl_true if the requested padding and buffer size were
        !           250:  * filled or \ref axl_false if end of file was reached. In that case the
        !           251:  * stream size is not updated.
        !           252:  */
        !           253: axl_bool axl_stream_prebuffer (axlStream * stream)
        !           254: {
        !           255:        int  bytes_read;
        !           256:        int  op_result;
        !           257: 
        !           258:        /* check some environment conditions */
        !           259:        axl_return_val_if_fail (stream, axl_false);
        !           260: 
        !           261:        /* no prebuffering is the stream type is not a file descriptor
        !           262:         * source and if the socket is closed */
        !           263:        if (stream->type != STREAM_FD || stream->fd == -1) {
        !           264:                return axl_false;
        !           265:        } /* end if */
        !           266: 
        !           267:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "prebuffering the stream..");
        !           268: 
        !           269:        /* displace memory only if there were data already consumed */
        !           270:        if (stream->stream_index > 0 && ((stream->stream_size - stream->stream_index) > 0)) {
        !           271: 
        !           272:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "   moving previous content at the begining of the buffer, current index: %d, size: %d, current status: %s",
        !           273:                           stream->stream_index, stream->stream_size - stream->stream_index,
        !           274:                           stream->stream + stream->stream_index);
        !           275: 
        !           276:                /* displace memory already read to be at the begining
        !           277:                 * of the stream */
        !           278:                memcpy (stream->temp, stream->stream + stream->stream_index,
        !           279:                        stream->stream_size - stream->stream_index);
        !           280: 
        !           281:                /* now copy displaced content back to the stream */
        !           282:                memcpy (stream->stream, stream->temp, 
        !           283:                        stream->stream_size - stream->stream_index);
        !           284: 
        !           285:                /* update the index to the positioned at the next byte
        !           286:                 * available on the buffer */
        !           287:                stream->stream_size  = (stream->stream_size - stream->stream_index);
        !           288:        } else {
        !           289:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "   nothing to prebuffer on the head (stream->size=%d, stream-index=%d, buffer-size=%d)",
        !           290:                           stream->stream_size, stream->stream_index, stream->buffer_size);
        !           291: 
        !           292:                /* check here if the buffer is full of content and a call to
        !           293:                 * prebuffer was done */
        !           294:                if (((stream->stream_size == stream->buffer_size) && 
        !           295:                    (stream->stream_index == 0)) || stream->needs_expansion) {
        !           296:                        /* looks like the caller is prebuffering
        !           297:                         * having all buffers full of content .. */
        !           298:                        
        !           299: 
        !           300:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
        !           301:                                   "   requested to prebuffer with buffers full of content (stream-index=%d, stream-size=%d, stream-buffer-size=%d, stream-needs-expansion=%d)",
        !           302:                                   stream->stream_index, stream->stream_size, stream->buffer_size, stream->needs_expansion);
        !           303: 
        !           304:                        /* unflag expansion requested */
        !           305:                        if (stream->needs_expansion)
        !           306:                                stream->needs_expansion = axl_false;
        !           307: 
        !           308:                        /* duplicate the buffer size */
        !           309:                        stream->buffer_size += (stream->buffer_size);
        !           310:                        stream->stream       = realloc (stream->stream, stream->buffer_size + 1);
        !           311:                        stream->temp         = realloc (stream->temp,   stream->buffer_size + 1);
        !           312: 
        !           313:                        if (stream->stream == NULL) {
        !           314:                                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
        !           315:                                   "   failed to update buffer sizes (realloc operation failed)",
        !           316:                                   stream->stream_index, stream->stream_size, stream->buffer_size);
        !           317:                                close (stream->fd);
        !           318:                                stream->fd = -1;
        !           319:                                return axl_false;
        !           320:                        } /* end if */
        !           321:                        
        !           322:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
        !           323:                                   "   buffer updated (stream-index=%d, stream-size=%d, stream-buffer-size=%d)",
        !           324:                                   stream->stream_index, stream->stream_size, stream->buffer_size);
        !           325:                } else {
        !           326:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG,
        !           327:                                   "   clearing stream-size=%d, having stream-index=%d and stream-buffer-size=%d",
        !           328:                                   stream->stream_size, stream->stream_index, stream->buffer_size);
        !           329: 
        !           330:                        /* reset if the stream size is just the content consumed */
        !           331:                        if (stream->stream_size == stream->stream_index)
        !           332:                                stream->stream_size  = 0; 
        !           333:                }
        !           334:        }
        !           335: 
        !           336:        /* reset current index */
        !           337:        stream->stream_index = 0;
        !           338: 
        !           339:        /* check if we have decode functions defined */
        !           340:        if (stream->decode_f) {
        !           341:                while (1) {
        !           342:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
        !           343:                                   "check temporal decode buffer for pending content: decode_temp_index=%d, decode_temp_last=%d, decode_temp_size=%d",
        !           344:                                   stream->decode_temp_index, 
        !           345:                                   stream->decode_temp_last,
        !           346:                                   stream->decode_temp_size);
        !           347: 
        !           348:                        if (stream->decode_temp_last > 0) {
        !           349:                                /* call to decode */
        !           350:                                if (! axl_stream_decode (stream, 
        !           351:                                                         /* output */
        !           352:                                                         stream->stream + stream->stream_size,
        !           353:                                                         /* max output size */
        !           354:                                                         stream->buffer_size - stream->stream_size,
        !           355:                                                         /* output decoded */
        !           356:                                                         &bytes_read, &op_result, NULL)) {
        !           357:                                        __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to decode content at the temporal decode buffer");
        !           358:                                        return axl_false;
        !           359:                                } /* end if */
        !           360: 
        !           361:                                /* check if the decode operation
        !           362:                                 * signaled that not enough espace was
        !           363:                                 * available to decode and no output
        !           364:                                 * was decoed, int his case flag the
        !           365:                                 * stream to do a stream expansion on
        !           366:                                 * the next call */
        !           367:                                if (op_result == 2 && bytes_read == 0)
        !           368:                                        stream->needs_expansion = axl_true;
        !           369: 
        !           370:                                /* add bytes read to the size */
        !           371:                                stream->stream_size += bytes_read;
        !           372: 
        !           373:                        } /* end if */
        !           374: 
        !           375:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, 
        !           376:                                   "after checking to decode, op_result=%d, bytes_read=%d, stream->buffer_size=%d, stream->stream_size=%d",
        !           377:                                   op_result, bytes_read, stream->buffer_size, stream->stream_size);
        !           378: 
        !           379:                        /* stop if no enought space if left and no
        !           380:                         * more bytes were translated */
        !           381:                        if (op_result == 2) 
        !           382:                                break;
        !           383: 
        !           384:                        /* check if there are still space to decode at the stream */
        !           385:                        if ((stream->buffer_size - stream->stream_size) > 0) {
        !           386:                                /* read content inside the decde temp buffer */
        !           387:                                bytes_read = read (stream->fd, stream->decode_temp + stream->decode_temp_last,
        !           388:                                                   stream->decode_temp_size - stream->decode_temp_last);
        !           389:                                
        !           390:                                /* update the amount of data available tat the decode temp */
        !           391:                                if (bytes_read > 0)
        !           392:                                        stream->decode_temp_last += bytes_read;
        !           393:                                else if (bytes_read == 0 && stream->fd > 0) {
        !           394:                                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "end of file reached");
        !           395:                                        close (stream->fd);
        !           396:                                        stream->fd = -1;
        !           397:                                } /* end if */
        !           398:                        } else {
        !           399:                                /* no more space is available at the reading buffer */
        !           400:                                break;
        !           401:                        } /* end if */
        !           402: 
        !           403:                        /* check to terminate */
        !           404:                        if (stream->decode_temp_index == 0 && 
        !           405:                            stream->decode_temp_last == 0 && 
        !           406:                            stream->fd == -1) 
        !           407:                                return axl_true;
        !           408:                        
        !           409:                } /* end while */
        !           410: 
        !           411:        } else {
        !           412: 
        !           413:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "   reading on buffer index: %d, size: %d (starting from: %d, length: %d)",
        !           414:                           stream->stream_index, stream->stream_size, stream->stream_size, stream->buffer_size - stream->stream_size);
        !           415: 
        !           416:                /* read current content */
        !           417:                bytes_read = read (stream->fd, stream->stream + stream->stream_size,
        !           418:                                   stream->buffer_size - stream->stream_size);
        !           419: 
        !           420: 
        !           421:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "   bytes read from the file, size %d", bytes_read);
        !           422: 
        !           423:                /* call to check */
        !           424:                if (stream->check_f) {
        !           425:                        /* call to check */
        !           426:                        if (! axl_stream_content_check (stream, stream->stream + stream->stream_size, bytes_read, NULL)) {
        !           427:                                __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to prebuffer, content check function have failed");
        !           428:                                return axl_false;
        !           429:                        }
        !           430:                } /* end if */
        !           431:                
        !           432:                /* check for end of file reached */
        !           433:                if (bytes_read == 0) {
        !           434:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "end of file reached");
        !           435:                        close (stream->fd);
        !           436:                        stream->fd = -1;
        !           437:                        return axl_false;
        !           438:                }
        !           439:                
        !           440:                /* set the new size, that is the padding, the content already
        !           441:                 * read, and the bytes already read */
        !           442:                stream->stream_size += bytes_read;
        !           443:        } /* end if */
        !           444: 
        !           445:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "   (before read) current buffer size: %d",
        !           446:                   stream->stream_size);
        !           447:        
        !           448:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "   prebuffered data: stream size: %d, new content: %s",
        !           449:                   bytes_read, stream->stream + stream->stream_index);
        !           450: 
        !           451:        return axl_true;
        !           452: }
        !           453: 
        !           454: /** 
        !           455:  * @brief Creates a new byte stream using as data the string pointer
        !           456:  * and the size.
        !           457:  * 
        !           458:  * The \ref axlStream object is an abstraction that allows to
        !           459:  * interface with a memory chunk, a file descriptor (or a socket) or a
        !           460:  * direct path, with a contenience API that allows inspecting and
        !           461:  * accepting the streamed content.
        !           462:  *
        !           463:  *
        !           464:  * Here is an example on how to create an stream from a memory chunk:
        !           465:  * \code
        !           466:  * axlStream * stream;
        !           467:  * axlError  * error;
        !           468:  *
        !           469:  * // create the stream and check result 
        !           470:  * stream = axl_stream_new (source_content, size_content, -1, NULL, &error);
        !           471:  * if (stream == NULL) {
        !           472:  *     printf ("An error was found: %s\n", axl_error_get (error));
        !           473:  *     axl_error_free (error);
        !           474:  *     return;
        !           475:  * }
        !           476:  * 
        !           477:  * // stream created
        !           478:  * \endcode
        !           479:  *
        !           480:  * In the case an stream is required to parse a file descriptor
        !           481:  * (including a socket):
        !           482:  * 
        !           483:  * \code
        !           484:  * stream = axl_stream_new (NULL, -1, NULL, fd, &error);
        !           485:  * \endcode
        !           486:  *
        !           487:  * You can also provide a file path to let the axl stream module to
        !           488:  * open the file and buffer it as it requires to consume characters:
        !           489:  *
        !           490:  * \code
        !           491:  * stream = axl_stream_new (NULL, -1, "c:/myFiles/document.xml", -1, &error);
        !           492:  * \endcode
        !           493:  * 
        !           494:  *
        !           495:  * Once initialized the \ref axlStream object, you can use the
        !           496:  * following function to check and consume characters:
        !           497:  * 
        !           498:  * - \ref axl_stream_inspect
        !           499:  * - \ref axl_stream_peek
        !           500:  * - \ref axl_stream_accept
        !           501:  * 
        !           502:  * There alternatives APIs that allows to get the content until some
        !           503:  * patter is found (or a set of patterns):
        !           504:  * 
        !           505:  * - \ref axl_stream_get_until
        !           506:  *
        !           507:  * 
        !           508:  * @param stream_source A pointer to the memory where the data to be
        !           509:  * streamed is located.
        !           510:  *
        !           511:  * @param stream_size How many bytes are available to perform
        !           512:  * streaming. You can pass a -1 value to allow the function to
        !           513:  * calculate the stream source size (stream_source param).
        !           514:  *
        !           515:  * @param file_path Optional parameter to allow reading the stream
        !           516:  * from a file using the open API.
        !           517:  *
        !           518:  * @param fd_handler Optional parameter to allow reading the stream
        !           519:  * from a file descriptor, that could be a file, a socket, etc..
        !           520:  *
        !           521:  * @param error Optional \ref axlError reference where errors will be reported.
        !           522:  * 
        !           523:  * @return A newly allocated stream instance that should be
        !           524:  * deallocated by using \ref axl_stream_free. The function could
        !           525:  * return a NULL value is received a NULL stream or a non positive
        !           526:  * stream size.
        !           527:  */
        !           528: axlStream * axl_stream_new (const char * stream_source, int stream_size,
        !           529:                            const char * file_path,     int fd_handler,
        !           530:                            axlError ** error)
        !           531: {
        !           532:        axlStream * stream;
        !           533:        int         fd;
        !           534: 
        !           535:        /* perform some environmental checkings */
        !           536:        if (file_path != NULL || (fd_handler > 0)) {
        !           537:                if (fd_handler < 0) {
        !           538:                        /* a file handle */
        !           539:                        if ((fd = open (file_path, O_RDONLY)) < 0) {
        !           540:                                axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "unable to open file a the location provided: %s, check location and permissions.", file_path);
        !           541: 
        !           542:                                axl_error_new (-1, "unable to read file provided", NULL, error);
        !           543:                                return NULL;
        !           544:                        }
        !           545:                }else
        !           546:                        fd = fd_handler;
        !           547: 
        !           548:                /* create the stream holder */
        !           549:                stream               = axl_new (axlStream, 1);
        !           550:                stream->buffer_size  = STREAM_BUFFER_SIZE;
        !           551:                stream->type         = STREAM_FD;
        !           552:                stream->fd           = fd;
        !           553: 
        !           554:                /* allocate 4k to perform streaming */
        !           555:                stream->stream       = axl_new (char, stream->buffer_size + 1);
        !           556:                stream->temp         = axl_new (char, stream->buffer_size + 1);
        !           557: 
        !           558:                /* prebuffer */
        !           559:                axl_stream_prebuffer (stream);
        !           560:        }else {
        !           561:                /* check chunk received */
        !           562:                if (stream_source == NULL) {
        !           563:                        axl_error_new (-1, "Requested to open a stream without providing an memory chunk, file descriptor or a file path", NULL, error);
        !           564:                        return NULL;
        !           565:                }
        !           566: 
        !           567:                /* check memory chunk size */
        !           568:                if (stream_size == -1)
        !           569:                        stream_size = strlen (stream_source);
        !           570: 
        !           571:                /* create the stream holder */
        !           572:                stream               = axl_new (axlStream, 1);
        !           573:                stream->buffer_size  = stream_size;
        !           574:                stream->type         = STREAM_MEM;
        !           575: 
        !           576:                /* copy source */
        !           577:                stream->stream       = axl_new (char, stream_size + 1);
        !           578:                memcpy (stream->stream, stream_source, stream_size);
        !           579:                /* nullify the last entry to avoid problems with
        !           580:                   printing functions and other APIs relaying on
        !           581:                   finding \0 at the end of the string */
        !           582:                stream->stream[stream_size] = 0;
        !           583:                
        !           584:                /* set initial indicators */
        !           585:                stream->stream_size  = stream_size;
        !           586:        }
        !           587: 
        !           588:        /* initilize common stream part */
        !           589:        stream->chunks  = axl_new (char *, MAX_INSPECTED_CHUNKS + 1);
        !           590:        stream->lengths = axl_new (int, MAX_INSPECTED_CHUNKS + 1);
        !           591: 
        !           592:        /* return newly created stream */
        !           593:        return stream;
        !           594: }
        !           595: 
        !           596: /** 
        !           597:  * @internal
        !           598:  *
        !           599:  * Internal implementation to support axl_stream_inspect and
        !           600:  * axl_stream_peek.
        !           601:  * 
        !           602:  * @param stream The stream where the inspect operation will be
        !           603:  * performed.
        !           604:  *
        !           605:  * @param chunk The chunk to be used while performing the inspect
        !           606:  * operation.
        !           607:  *
        !           608:  * @param inspected_size The size for the chunk to be checked or -1 if
        !           609:  * a chunk size calculation is required.
        !           610:  *
        !           611:  * @param alsoAccept axl_true to make the function to accept stream
        !           612:  * that is properly inspected, axl_false if not.
        !           613:  * 
        !           614:  * @return See \ref axl_stream_inspect.
        !           615:  */
        !           616: #define axl_stream_common_inspect(i,stream,chunk,inspected_size,alsoAccept)\
        !           617: if (inspected_size == -1)\
        !           618:        inspected_size = strlen (chunk);\
        !           619: if (axl_stream_fall_outside (stream, inspected_size))\
        !           620:        return -1;\
        !           621: i = 0;\
        !           622: while (chunk [i] != 0 && (stream->stream + stream->stream_index) [i] != 0) {\
        !           623:      if (chunk [i] != (stream->stream + stream->stream_index) [i])\
        !           624:         return 0;\
        !           625:      i++;\
        !           626:      if (i == inspected_size) {\
        !           627:        stream->previous_inspect = inspected_size;\
        !           628:        if (alsoAccept) {\
        !           629:                axl_stream_accept (stream);\
        !           630:        }\
        !           631:        return 1;\
        !           632:      }\
        !           633: }\
        !           634:        return 0
        !           635: 
        !           636: 
        !           637: /** 
        !           638:  * @brief Allows to perform an inspection of the given chunk on the
        !           639:  * given stream.
        !           640:  *
        !           641:  * The <i>chunk</i> will be checked to apper at the begining of the
        !           642:  * stream. This means that, having the current state of the stream,
        !           643:  * the chunk is checked to be found at the very begining of the
        !           644:  * stream.
        !           645:  *
        !           646:  * If the function succeed, an implict call to \ref axl_stream_accept
        !           647:  * is done. In the case you are only checking but no stream acceptance
        !           648:  * is required, use instead: \ref axl_stream_peek.
        !           649:  * 
        !           650:  * @param stream The \ref axlStream where the operation will be
        !           651:  * performed.
        !           652:  * 
        !           653:  * @param chunk The chunk that is expected to be found at the begin of the stream.
        !           654:  * 
        !           655:  * @param inspected_size The size of the chunk provided to be inspected.
        !           656:  * 
        !           657:  * @return The function returns the following values according to the result: 
        !           658:  *
        !           659:  * - <b>0</b> if the chunk wasn't found inside the stream but no error was
        !           660:  * found.
        !           661:  *
        !           662:  * - <b>1</b> if the chunk is found inside the given stream.
        !           663:  *
        !           664:  * - <b>-1</b> means that no more stream is left to satify the operation.
        !           665:  *
        !           666:  * - <b>-2</b> means that the parameters received are wrong either
        !           667:  * because stream is a NULL reference or because chunk is the same.
        !           668:  */
        !           669: int         axl_stream_inspect (axlStream * stream, const char * chunk, int inspected_size)
        !           670: {
        !           671:        int iterator;
        !           672: 
        !           673:        /* call to common implementation */
        !           674:        axl_stream_common_inspect (iterator, stream, chunk, inspected_size, axl_true);
        !           675: }
        !           676: 
        !           677: /** 
        !           678:  * @brief Allows to check the provide char code at the given \ref
        !           679:  * axlStream, using optionally an offset to perform the check.
        !           680:  * 
        !           681:  * @param stream The stream where the check operation will be
        !           682:  * implemented.
        !           683:  *
        !           684:  * @param value The value to check.
        !           685:  *
        !           686:  * @param offset The stream offset to apply to the check. Use 0 to not
        !           687:  * apply offset.
        !           688:  * 
        !           689:  * @return \ref axl_true if the provided value is found at the current
        !           690:  * stream index (taking into consideration offset).
        !           691:  */
        !           692: axl_bool         axl_stream_inspect_code    (axlStream * stream, char value, int offset)
        !           693: {
        !           694:        axl_return_val_if_fail (stream, axl_false);
        !           695:        
        !           696:        /* check the value */
        !           697:        return stream->stream [stream->stream_index + offset] == value;
        !           698: }
        !           699: 
        !           700: /** 
        !           701:  * @brief Allows to perform a stream inspection without automatically
        !           702:  * accept content properly inspected.
        !           703:  * 
        !           704:  * @param stream The stream where the peek operation will be
        !           705:  * performed.
        !           706:  *
        !           707:  * @param chunk The chunk to lookup.
        !           708:  *
        !           709:  * @param inspected_size The size of the chunk provided to be
        !           710:  * inspected.
        !           711:  * 
        !           712:  * @return See \ref axl_stream_inspect.
        !           713:  */
        !           714: int         axl_stream_peek            (axlStream * stream, const char * chunk, int inspected_size)
        !           715: {
        !           716:        int iterator;
        !           717: 
        !           718:        /* call to common implementation */
        !           719:        axl_stream_common_inspect (iterator, stream, chunk, inspected_size, axl_false);
        !           720: }
        !           721: 
        !           722: /** 
        !           723:  * @brief Allows to perform several, not excluyen inspect operations,
        !           724:  * over the given stream.
        !           725:  *
        !           726:  * Here is an example:
        !           727:  * \code
        !           728:  * if (axl_stream_inspect_several (stream,         // the stream 
        !           729:  *                                 2,              // two chunks to recognize 
        !           730:  *                                 "or", 2,        // first chunk and its length
        !           731:  *                                 "||", 2) > 0) { // second chunk and its length
        !           732:  *      // chunk matched!!
        !           733:  * }
        !           734:  * \endcode
        !           735:  * @param stream The stream where the operation will be performed.
        !           736:  *
        !           737:  * @param chunk_num The chunk number to inspect.
        !           738:  * 
        !           739:  * @return The function returns the following values: 
        !           740:  * 
        !           741:  * - <b>0</b>: if no chunk is found inside the given stream, according to the
        !           742:  * provided chunks.
        !           743:  *
        !           744:  * - <b>N</b>: is returned to denote that the Nth chunk was found.
        !           745:  *
        !           746:  * - <b>-1</b>: is returned if no more stream is left to satisfy the operation.
        !           747:  * 
        !           748:  * - <b>-2</b>: means that the parameters received are wrong either because
        !           749:  * stream is NULL or any other parameter.
        !           750:  */
        !           751: int         axl_stream_inspect_several (axlStream * stream, int chunk_num, ...)
        !           752: {
        !           753:        va_list   args;
        !           754:        int       iterator   = 0;
        !           755:        char    * chunk      = NULL;
        !           756:        int       length     = 0;
        !           757:        int       last_value = 0;
        !           758: 
        !           759:        axl_return_val_if_fail (stream,        -1);
        !           760:        axl_return_val_if_fail (chunk_num > 0, -1);
        !           761: 
        !           762:        va_start (args, chunk_num);
        !           763: 
        !           764:        /* check each chunk */
        !           765:        while (iterator < chunk_num) {
        !           766: 
        !           767:                /* get the next chunk */
        !           768:                chunk  = va_arg (args, char *);
        !           769:                length = va_arg (args, int);
        !           770: 
        !           771:                if (length == -1)
        !           772:                        length = strlen (chunk);
        !           773:                
        !           774:                /* check the chunk read */
        !           775:                switch (axl_stream_inspect (stream, chunk, length)) {
        !           776:                case -2:
        !           777:                        /* wrong parameter received */
        !           778:                        last_value = -2;
        !           779:                        break;
        !           780:                case -1:
        !           781:                        /* there is no more stream left */
        !           782:                        last_value = -1;
        !           783:                        break;
        !           784:                case 0:
        !           785:                        /* the chunk wasn't found, break and
        !           786:                         * continue. */
        !           787:                        break;
        !           788:                default:
        !           789:                        /* the chunk was found */
        !           790:                        va_end (args);
        !           791:                        return (iterator + 1);
        !           792:                }
        !           793:                
        !           794:                /* update the iterator */
        !           795:                iterator ++;
        !           796:        }
        !           797: 
        !           798:        /* close va arg */
        !           799:        va_end (args);
        !           800: 
        !           801:        /* return that no chunk was found */
        !           802:        return last_value;
        !           803: }
        !           804: 
        !           805: /** 
        !           806:  * @brief Accept previous inspected chunk to be consumed and moves
        !           807:  * current stream current the size equal to the chunk inspected.
        !           808:  * 
        !           809:  * @param stream The stream where the byte inspected size will be
        !           810:  * accepted.
        !           811:  */
        !           812: void axl_stream_accept (axlStream * stream)
        !           813: {
        !           814:        axl_return_if_fail (stream);
        !           815: 
        !           816:        /* simple memory chunk parsing */
        !           817:        stream->stream_index     += stream->previous_inspect;
        !           818:        stream->global_index     += stream->previous_inspect;
        !           819: 
        !           820:        stream->previous_inspect  = 0;
        !           821:        if (stream->last_chunk != NULL)
        !           822:                axl_free (stream->last_chunk);
        !           823:        stream->last_chunk = NULL;
        !           824: 
        !           825:        return;
        !           826: }
        !           827: 
        !           828: /** 
        !           829:  * @brief Push new content at the begin of the stream.
        !           830:  * 
        !           831:  * @param stream The stream that will be updated with new content.
        !           832:  *
        !           833:  * @param content The content to be added.
        !           834:  *
        !           835:  * @param size The size of the content to be added.
        !           836:  */
        !           837: void axl_stream_push (axlStream * stream, const char * content, int size)
        !           838: {
        !           839:        axl_return_if_fail (stream && content);
        !           840:        
        !           841:        /* place the content at the begin of the stream */
        !           842:        axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "calling to push the stream..");
        !           843: 
        !           844:        /* check if the current stream buffer could hold the pushed
        !           845:         * content plus the content that is already placed */
        !           846:        if (stream->stream_size < (stream->stream_size - stream->stream_index + size)) {
        !           847:                /* seems we can't hold the content at this moment, so, update the stream size */
        !           848:                stream->buffer_size = stream->stream_size - stream->stream_index + size;
        !           849: 
        !           850:                /* alloc a new temporal buffer */
        !           851:                axl_free (stream->temp);
        !           852:                stream->temp = axl_new (char, stream->buffer_size + 1);
        !           853:                memcpy (stream->temp, content, size);
        !           854:                
        !           855:                /* displace memory already read to be at the begining
        !           856:                 * of the stream */
        !           857:                memcpy (stream->temp + size, stream->stream + stream->stream_index,
        !           858:                        stream->stream_size - stream->stream_index);
        !           859: 
        !           860:                /* now realloc the buffer */
        !           861:                axl_free (stream->stream);
        !           862:                stream->stream = axl_new (char, stream->buffer_size + 1);
        !           863: 
        !           864:                /* now copy displaced content back to the stream */
        !           865:                memcpy (stream->stream, stream->temp, 
        !           866:                        (stream->stream_size - stream->stream_index) + size);
        !           867:        } else {
        !           868: 
        !           869:                /* check for the temporal buffer to be created */
        !           870:                if (stream->temp == NULL)
        !           871:                        stream->temp = axl_new (char, stream->buffer_size + 1);
        !           872: 
        !           873:                /* copy the content */
        !           874:                memcpy (stream->temp, content, size);
        !           875: 
        !           876:                /* displace memory already read to be at the begining
        !           877:                 * of the stream */
        !           878:                memcpy (stream->temp + size, stream->stream + stream->stream_index,
        !           879:                        stream->stream_size - stream->stream_index);
        !           880: 
        !           881:                /* now copy displaced content back to the stream */
        !           882:                memcpy (stream->stream, stream->temp, 
        !           883:                        (stream->stream_size - stream->stream_index) + size);
        !           884: 
        !           885:        } /* end if */
        !           886: 
        !           887:        /* update the index to the positioned at the next byte
        !           888:         * available on the buffer */
        !           889:        stream->stream_size  = (stream->stream_size - stream->stream_index) + size;
        !           890: 
        !           891:        /* reset the index */
        !           892:        stream->stream_index = 0;
        !           893: 
        !           894:        /* clean previous state */
        !           895:        axl_stream_accept (stream);
        !           896: 
        !           897:        return;
        !           898: }
        !           899: 
        !           900: /** 
        !           901:  * @brief Allows to configure current index to be accepted by the
        !           902:  * stream. 
        !           903:  * 
        !           904:  * @param stream The stream where the operation will be performed.
        !           905:  *
        !           906:  * @param index Count to move internal stream index.
        !           907:  *
        !           908:  * NOTE: the function reset current internal state (by doing an
        !           909:  * implicit call to \ref axl_stream_accept).
        !           910:  */
        !           911: void        axl_stream_move            (axlStream * stream, int index)
        !           912: {
        !           913:        axl_return_if_fail (stream);
        !           914: 
        !           915:        axl_stream_accept (stream);
        !           916:        stream->stream_index     = index;
        !           917:        
        !           918:        return;
        !           919: }
        !           920: 
        !           921: /** 
        !           922:  * @brief Makes the current index to be moved the amount of bytes
        !           923:  * signaled by the parameter bytes.
        !           924:  * 
        !           925:  * @param stream The stream to update.
        !           926:  * @param bytes The number of bytes to move the index. 
        !           927:  */
        !           928: void        axl_stream_step            (axlStream * stream, int bytes)
        !           929: {
        !           930:        axl_return_if_fail (stream);
        !           931:        axl_return_if_fail (bytes >= 0);
        !           932: 
        !           933:        axl_stream_accept (stream);
        !           934:        stream->stream_index += bytes;
        !           935: 
        !           936:        return;
        !           937: }
        !           938: 
        !           939: /** 
        !           940:  * @brief Returns the next chunk available on the stream.
        !           941:  *
        !           942:  * This function allows to get next available chunk, validating it
        !           943:  * with provided valid_chars variable, until the chunk provided are
        !           944:  * found.
        !           945:  *
        !           946:  * Currently, valid_chars is not used, so, the chunk returned is not
        !           947:  * validated against the value provided.
        !           948:  * 
        !           949:  * As an example if it is required to get the encoding content, you
        !           950:  * could do the next call:
        !           951:  * 
        !           952:  * \code
        !           953:  * // reference to the allocated result
        !           954:  * char * result;
        !           955:  * 
        !           956:  * // chunk matched variable
        !           957:  * int chunk_matched;
        !           958:  * 
        !           959:  * // get the next chunk until a " or ' is found
        !           960:  * result = axl_stream_get_until (stream, NULL, &chunk_matched, AXL_TRUE, 2, "\"", "'");
        !           961:  * \endcode
        !           962:  *
        !           963:  * Value returned from this function mustn't be deallocated. However,
        !           964:  * because the value returned is dinamically allocated by the
        !           965:  * function, you can avoid doing a double allocation operation by
        !           966:  * nullifying the internal reference to the result returned, making
        !           967:  * the caller the only owner of the reference returned. To do this
        !           968:  * use: \ref axl_stream_nullify with \ref LAST_CHUNK.
        !           969:  * 
        !           970:  * 
        !           971:  * @param stream The stream were the chunk will be extracted.
        !           972:  *
        !           973:  * @param valid_chars The valid set of characters, to validate content
        !           974:  * to be returned. Currently this is not implemented, so, you can
        !           975:  * provide a NULL value.
        !           976:  *
        !           977:  * @param chunk_matched An optional pointer to an integer to notify
        !           978:  * the chunk matched by the function. Chunk matching notification
        !           979:  * starts from 0 up to number of chunks to match - 1. If the end of
        !           980:  * the stream is reached, -2 is returned.
        !           981:  * 
        !           982:  * @param accept_terminator While calling to this function, the
        !           983:  * terminator detected to stop the operation could also be accepted by
        !           984:  * the stream, making it not necessary to accept the terminator once
        !           985:  * the function have ended. However, this could be a problem while
        !           986:  * performing peeking code. You can provide a AXL_FALSE value to make the
        !           987:  * function to not accept the terminator found as to be consumed.
        !           988:  *
        !           989:  * @param chunk_num The number of chunks to be checked as a valid terminators.
        !           990:  * 
        !           991:  * @return The chunk recognizied, not including the terminator that
        !           992:  * have made this operation to stop. 
        !           993:  */
        !           994: char      * axl_stream_get_until       (axlStream * stream, 
        !           995:                                        char      * valid_chars, 
        !           996:                                        int       * chunk_matched,
        !           997:                                        axl_bool    accept_terminator,
        !           998:                                        int         chunk_num, ...)
        !           999: {
        !          1000:        char * result;
        !          1001:        va_list args;
        !          1002:        
        !          1003:        /* open the standard argument */
        !          1004:        va_start (args, chunk_num);
        !          1005: 
        !          1006:        /* call to get next chunk separated by the provided values */
        !          1007:        result = axl_stream_get_untilv (stream, valid_chars, chunk_matched, accept_terminator, NULL, chunk_num, args);
        !          1008: 
        !          1009:        /* close the standard argument */
        !          1010:        va_end (args);
        !          1011: 
        !          1012:        /* return value read */
        !          1013:        return result;
        !          1014: }
        !          1015: 
        !          1016: /** 
        !          1017:  * @brief Works the same way like axl_strteam_get_until but wihtout
        !          1018:  * allocating the memory returned, and filling the size for the chunk
        !          1019:  * returned in result_size reference.
        !          1020:  * 
        !          1021:  * @param stream The stream where the operation will be performed.
        !          1022:  *
        !          1023:  * @param valid_chars The valid chars reference to match (currently
        !          1024:  * not implemented).
        !          1025:  *
        !          1026:  * @param chunk_matched The chunk matched reference 
        !          1027:  *
        !          1028:  * @param accept_terminator Configure if the terminator should be
        !          1029:  * accepted or not.
        !          1030:  *
        !          1031:  * @param result_size The variable where the result size will be
        !          1032:  * returned. This variable is not optional. It must be configured to
        !          1033:  * hold the size of the content returned. If you provided a NULL
        !          1034:  * reference to this value then the function will fail. 
        !          1035:  *
        !          1036:  * @param chunk_num The number of chunks to match.
        !          1037:  * 
        !          1038:  * @return A reference to the internal stream copy. The reference
        !          1039:  * returned must not be deallocated.
        !          1040:  *
        !          1041:  * NOTE: This function have a particular function that could produce
        !          1042:  * not desired results. Because the stream returns a reference to the
        !          1043:  * current allocated stream, if nullifies the last position (\\0) to
        !          1044:  * avoid memory problems with printf APIs and any other code that
        !          1045:  * relay on the fact that C strings are NULL terminated. If the
        !          1046:  * content immediately following to the string returned is meaningful,
        !          1047:  * then you can't use this function. Example:
        !          1048:  * 
        !          1049:  * \code
        !          1050:  *   stream: CONTENTCONTENT2
        !          1051:  *           ^
        !          1052:  *           |
        !          1053:  *           +--- stream index
        !          1054:  *   
        !          1055:  *   calling to axl_stream_get_until_ref (stream, NULL, NULL, axl_false,
        !          1056:  *                                        &size, 1, "CONTENT");
        !          1057:  * 
        !          1058:  *   while cause stream: CONTENT\0ONTENT2
        !          1059:  *                               ^
        !          1060:  *                               |
        !          1061:  *                               +--- stream index
        !          1062:  * 
        !          1063:  *   and the function returning "CONTENT". See the fact that the
        !          1064:  *   next "C" from the word CONTENT2 is nullified.
        !          1065:  *
        !          1066:  * \endcode
        !          1067:  *
        !          1068:  * An indication that this function is not what you want is that you
        !          1069:  * are not accepting the terminator (accept_terminator=axl_false).
        !          1070:  */
        !          1071: char      * axl_stream_get_until_ref   (axlStream * stream, 
        !          1072:                                        char      * valid_chars, 
        !          1073:                                        int       * chunk_matched,
        !          1074:                                        axl_bool    accept_terminator,
        !          1075:                                        int       * result_size,
        !          1076:                                        int         chunk_num, ...)
        !          1077: {
        !          1078:        char * result;
        !          1079:        va_list args;
        !          1080: 
        !          1081:        axl_return_val_if_fail (result_size, NULL);
        !          1082:        
        !          1083:        /* open the standard argument */
        !          1084:        va_start (args, chunk_num);
        !          1085: 
        !          1086:        /* call to get next chunk separated by the provided values */
        !          1087:        result = axl_stream_get_untilv (stream, valid_chars, chunk_matched, accept_terminator, result_size, chunk_num, args);
        !          1088: 
        !          1089:        /* close the standard argument */
        !          1090:        va_end (args);
        !          1091: 
        !          1092:        /* return value read */
        !          1093:        return result;
        !          1094: }
        !          1095: 
        !          1096: /** 
        !          1097:  * @brief Allows to get the next string until the separators provided
        !          1098:  * are found or the end of the stream memory is reached.
        !          1099:  *
        !          1100:  * \ref axlStream type was designed to support parsing xml
        !          1101:  * documents. This documents have elements that allows to now where
        !          1102:  * the input has finished. Howerver, \ref axlStream abstraction has
        !          1103:  * showed to be powerful enough to be usable to parse other kinds of
        !          1104:  * elements that don't have lexical terminators to let the user to
        !          1105:  * provide that chunk to be matched.
        !          1106:  *
        !          1107:  * In those cases, this function allows to perform the same function
        !          1108:  * as \ref axl_stream_get_until but also checking, and using, as
        !          1109:  * terminator the end of the stream.
        !          1110:  * 
        !          1111:  * This allows to parse expressions like:
        !          1112:  * \code
        !          1113:  * int         chunk_matched;
        !          1114:  * axlStream * stream;
        !          1115:  * char      * string;
        !          1116:  * 
        !          1117:  * // create the stream 
        !          1118:  * stream = axl_stream_new ("array.value", -1, NULL, -1, &error);
        !          1119:  *
        !          1120:  * // parse first array identifier 
        !          1121:  * string = axl_stream_get_until_zero (stream, NULL, &chunk_matched, 
        !          1122:  *                                     axl_false, 2, "[", ".", NULL);
        !          1123:  *
        !          1124:  * // received "array"
        !          1125:  *
        !          1126:  * // parse again 
        !          1127:  * string = axl_stream_get_until_zero (stream, NULL, &chunk_matched, 
        !          1128:  *                                     axl_false, 2, "[", ".", NULL);
        !          1129:  *
        !          1130:  * // received "value" and chunk_matched == (-2)
        !          1131:  * \endcode
        !          1132:  *  
        !          1133:  * 
        !          1134:  * @param stream The stream were the chunk will be extracted.
        !          1135:  *
        !          1136:  * @param valid_chars The valid set of characters, to validate content
        !          1137:  * to be returned. Currently this is not implemented, so, you can
        !          1138:  * provide a NULL value.
        !          1139:  *
        !          1140:  * @param chunk_matched An optional pointer to an integer to notify
        !          1141:  * the chunk matched by the function. Chunk matching notification
        !          1142:  * starts from 0 up to number of chunks to match - 1. If the end of
        !          1143:  * the stream is reached while searching for the content to match,
        !          1144:  * chunk_matched is configured to -2.
        !          1145:  * 
        !          1146:  * @param accept_terminator While calling to this function, the
        !          1147:  * terminator detected to stop the operation could also be accepted by
        !          1148:  * the stream, making it not necessary to accept the terminator once
        !          1149:  * the function have ended. However, this could be a problem while
        !          1150:  * performing peeking code. You can provide a AXL_FALSE value to make the
        !          1151:  * function to not accept the terminator found as to be consumed.
        !          1152:  *
        !          1153:  * @param chunk_num The number of chunks to be checked as a valid terminators.
        !          1154:  * 
        !          1155:  * @return The chunk recognizied, not including the terminator that
        !          1156:  * have made this operation to stop. Rembember to check the
        !          1157:  * chunk_matched variable to be equal to -2. This will mean that the
        !          1158:  * string returned doesn't match any terminator provided because end
        !          1159:  * of the stream was reached while looking for them.
        !          1160:  */
        !          1161: char      * axl_stream_get_until_zero  (axlStream * stream, 
        !          1162:                                        char      * valid_chars, 
        !          1163:                                        int       * chunk_matched,
        !          1164:                                        axl_bool    accept_terminator,
        !          1165:                                        int         chunk_num, ...)
        !          1166: {
        !          1167:        char * result;
        !          1168:        va_list args;
        !          1169:        
        !          1170:        /* open the standard argument */
        !          1171:        va_start (args, chunk_num);
        !          1172: 
        !          1173:        /* call to get next chunk separated by the provided values */
        !          1174:        stream->zero = axl_true;
        !          1175:        result       = axl_stream_get_untilv (stream, valid_chars, chunk_matched, accept_terminator, NULL, chunk_num, args);
        !          1176:        stream->zero = axl_false;
        !          1177: 
        !          1178:        /* close the standard argument */
        !          1179:        va_end (args);
        !          1180: 
        !          1181:        /* return value read */
        !          1182:        return result;
        !          1183: }
        !          1184: 
        !          1185: char      * axl_stream_get_until_ref_zero  (axlStream * stream, 
        !          1186:                                            char      * valid_chars, 
        !          1187:                                            int       * chunk_matched,
        !          1188:                                            axl_bool    accept_terminator,
        !          1189:                                            int       * result_size,
        !          1190:                                            int         chunk_num, ...)
        !          1191: {
        !          1192:        char * result;
        !          1193:        va_list args;
        !          1194:        
        !          1195:        /* open the standard argument */
        !          1196:        va_start (args, chunk_num);
        !          1197: 
        !          1198:        /* call to get next chunk separated by the provided values */
        !          1199:        stream->zero = axl_true;
        !          1200:        result       = axl_stream_get_untilv (stream, valid_chars, chunk_matched, accept_terminator, result_size, chunk_num, args);
        !          1201:        stream->zero = axl_false;
        !          1202: 
        !          1203:        /* close the standard argument */
        !          1204:        va_end (args);
        !          1205: 
        !          1206:        /* return value read */
        !          1207:        return result;
        !          1208: }
        !          1209: 
        !          1210: /** 
        !          1211:  * @brief Allows to configure the handler to be executed to alloc
        !          1212:  * memory for the axl_stream_get_until* API.
        !          1213:  * 
        !          1214:  * @param stream The stream to configure with the alloc function.
        !          1215:  *
        !          1216:  * @param handler The handler to be called when the streams requires
        !          1217:  * to alloc memory.
        !          1218:  *
        !          1219:  * @param data User defined pointer to be called to the allocator
        !          1220:  * function defined by the <b>handler</b> parameter.
        !          1221:  */
        !          1222: void       axl_stream_set_buffer_alloc   (axlStream      * stream,
        !          1223:                                          axlStreamAlloc   handler,
        !          1224:                                          axlPointer       data)
        !          1225: {
        !          1226:        axl_return_if_fail (stream);
        !          1227: 
        !          1228:        /* just configure the alloc handler */
        !          1229:        stream->alloc      = handler;
        !          1230:        stream->alloc_data = data;
        !          1231: 
        !          1232:        return;
        !          1233: }
        !          1234: 
        !          1235: /** 
        !          1236:  * @brief Allows to nullify the internal reference of the stream,
        !          1237:  * making that reference to be not deallocated once the stream is
        !          1238:  * moving.
        !          1239:  *
        !          1240:  * This is mainly used to reduce the malloc/free round trip while
        !          1241:  * using the stream abstraction, making the stream received from the
        !          1242:  * memory chunk to be allocated only once, avoiding the double
        !          1243:  * allocate-free cycle.
        !          1244:  * 
        !          1245:  * @param stream The \ref axlStream where the operation will be
        !          1246:  * performed.
        !          1247:  *
        !          1248:  * @param item The item to nullify. 
        !          1249:  */
        !          1250: void        axl_stream_nullify         (axlStream * stream,
        !          1251:                                        NullifyItem item)
        !          1252: {
        !          1253:        /* do not operate if a null stream reference is received */
        !          1254:        axl_return_if_fail (stream);
        !          1255: 
        !          1256:        switch (item) {
        !          1257:        case LAST_CHUNK:
        !          1258:                stream->last_chunk         = NULL;
        !          1259:                break;
        !          1260:        case LAST_NEAR_TO:
        !          1261:                stream->last_near_to       = NULL;
        !          1262:                break;
        !          1263:        case LAST_GET_FOLLOWING:
        !          1264:                stream->last_get_following = NULL;
        !          1265:                break;
        !          1266:        }
        !          1267:        
        !          1268:        /* nothing more to do here */
        !          1269:        return;
        !          1270: }
        !          1271: 
        !          1272: /** 
        !          1273:  * @internal 
        !          1274:  * 
        !          1275:  * Wide implementation for axl stream get until (which checks for
        !          1276:  * every index chunks provided instead of checking the first one until
        !          1277:  * a prebuffer operation is required).
        !          1278:  */
        !          1279: char * __axl_stream_get_untilv_wide (axlStream * stream, va_list args)
        !          1280: {
        !          1281: 
        !          1282:        int          iterator    = 0;
        !          1283:        int          index       = 0;
        !          1284:        int          _index      = 0;
        !          1285:        int          length      = 0;
        !          1286:        int          max_length  = 0;
        !          1287:        axl_bool     matched;
        !          1288:        char       * string      = NULL;
        !          1289:        axl_bool     match_empty = axl_false;
        !          1290:        int          empty_index = 0;
        !          1291: 
        !          1292:        /* get how many bytes remains to be read */
        !          1293:        int          remains;
        !          1294:        
        !          1295:        /* set current matched value */
        !          1296:        stream->chunk_matched = -1;
        !          1297:        
        !          1298:        /* iterate over the chunk list */
        !          1299:        while (iterator < stream->chunk_num) {
        !          1300: 
        !          1301:                /* get the chunk */
        !          1302:                stream->chunks [iterator]  = va_arg (args, char *);
        !          1303: 
        !          1304:                /* check if we have to match the emtpy string, and
        !          1305:                 * don't install the value to be matched */
        !          1306:                if (axl_cmp (stream->chunks[iterator], " ")) {
        !          1307:                        match_empty = axl_true;
        !          1308: 
        !          1309:                        /* reset the length size to detect an emtpy
        !          1310:                         * string */
        !          1311:                        stream->lengths [iterator] = 0;
        !          1312:                        empty_index                = iterator;
        !          1313:                }else {
        !          1314:                        /* get the size */
        !          1315:                        stream->lengths [iterator] = strlen (stream->chunks [iterator]);
        !          1316:                }
        !          1317: 
        !          1318:                /* get current length */
        !          1319:                if (stream->lengths [iterator] > max_length)
        !          1320:                        max_length = stream->lengths [iterator];
        !          1321: 
        !          1322:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found matching chunk: '%s' length: %d", 
        !          1323:                           stream->chunks[iterator], stream->lengths [iterator]);
        !          1324: 
        !          1325:                /* update index */
        !          1326:                iterator ++;
        !          1327:        }
        !          1328: 
        !          1329:        /* calculate how many bytes ara available */
        !          1330:        remains = stream->stream_size - stream->stream_index;
        !          1331: 
        !          1332:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "remaining data to be inspected: %d bytes (stream->stream-size=%d, stream->stream-index=%d)",
        !          1333:                   remains, stream->stream_size, stream->stream_index);
        !          1334: 
        !          1335:        /* now we have chunks to lookup, stream until get the stream
        !          1336:         * limited by the chunks received. */
        !          1337:        do {
        !          1338: 
        !          1339:                /* decrease remain bytes to be read until perform a
        !          1340:                 * prebuffer operation */
        !          1341:                remains--;
        !          1342: 
        !          1343:                /* only prebuffer for this type of stream */
        !          1344:                if (stream->type == STREAM_FD) {
        !          1345:                        
        !          1346:                        /* check if the index is falling out side the buffer boundaries */
        !          1347:                        if (remains < 0) {
        !          1348: 
        !          1349:                                if (! axl_stream_prebuffer (stream)) {
        !          1350:                                        /* check if a call to zero was found */
        !          1351:                                        if (stream->zero) {
        !          1352:                                                /* flag that chunk matched
        !          1353:                                                 * will be -2 */
        !          1354:                                                stream->chunk_matched = -2;
        !          1355:                                                goto matched_return_result;
        !          1356:                                        } /* end if */
        !          1357:                                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "failed while prebuffer (stream->type = %d)", stream->type);
        !          1358: 
        !          1359:                                        return NULL;
        !          1360:                                }
        !          1361:                                
        !          1362:                                /* update remains value but this time removing
        !          1363:                                 * one unit (the unit to be consumed at the
        !          1364:                                 * next sentence) */
        !          1365:                                remains = stream->stream_size - index - 1;
        !          1366: 
        !          1367:                                /* work around: because the index is updated
        !          1368:                                 * at the end of the loop, it is required to
        !          1369:                                 * decrease the index in one unit in the case
        !          1370:                                 * a prebuffer operation happens */
        !          1371:                                if (index > 0) {
        !          1372:                                        index--;
        !          1373:                                }
        !          1374:                                
        !          1375:                        } /* end if */
        !          1376:                }
        !          1377: 
        !          1378:                /* check we don't get out side the memory */
        !          1379:                if (stream->type == STREAM_MEM) {
        !          1380:                        if (remains < 0) {
        !          1381: 
        !          1382:                                /* check for zero stream ended
        !          1383:                                 * support */
        !          1384:                                if (stream->zero) {
        !          1385:                                        /* flag that chunk matched
        !          1386:                                         * will be -2 */
        !          1387:                                        stream->chunk_matched = -2;
        !          1388:                                        goto matched_return_result;
        !          1389:                                }
        !          1390: 
        !          1391:                                /* seems there is no more room to
        !          1392:                                 * read */
        !          1393:                                return NULL;
        !          1394:                        } /* end if */
        !          1395:                } /* end if */
        !          1396: 
        !          1397:                
        !          1398:                /* compare chunks received for each index increased
        !          1399:                 * one step */
        !          1400:        init_get_until:
        !          1401:                _index   = stream->stream_index + index;
        !          1402:                matched  = axl_false;
        !          1403:                iterator = 0;
        !          1404: 
        !          1405:                /* before iterating, check if we have to match the
        !          1406:                 * empty string */
        !          1407:                if (match_empty) {
        !          1408:                        /* check for a white space item */
        !          1409:                        if ((stream->stream[_index] == ' ')  ||
        !          1410:                            (stream->stream[_index] == '\n') ||
        !          1411:                            (stream->stream[_index] == '\t') ||
        !          1412:                            (stream->stream[_index] == '\r')) {
        !          1413: 
        !          1414:                                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "matched by white space value matched_chunk=%d",
        !          1415:                                           iterator);
        !          1416: 
        !          1417:                                /* string matched */
        !          1418:                                length         = 1;
        !          1419:                                matched        = axl_true;
        !          1420:                                iterator       = empty_index;
        !          1421:                        }
        !          1422:                } /* end if */
        !          1423: 
        !          1424:                /* the empty string wasn't matched, now check for the
        !          1425:                 * rest of chunks */
        !          1426:                while ((! matched) && (iterator < stream->chunk_num)) {
        !          1427:                        
        !          1428:                        /* get current length for the chunk to check */
        !          1429:                        length  = stream->lengths [iterator];
        !          1430: 
        !          1431:                        /* check the length returned */
        !          1432:                        matched = axl_false;
        !          1433:                        if (length > 0 && ((_index + length) <= stream->stream_size)) {
        !          1434:                                
        !          1435:                                /* try to figure out if the next
        !          1436:                                 * string match */
        !          1437:                                if ((stream->chunks [iterator][0] == 
        !          1438:                                     stream->stream [_index])) {
        !          1439:                                        
        !          1440:                                        if ((length == 1) ||
        !          1441:                                            (axl_memcmp (stream->chunks [iterator] + 1, stream->stream + _index + 1, length -1))) {
        !          1442:                                                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "matched as normal situation.. at index=%d (stream size=%d)",
        !          1443:                                                           stream->stream_index + _index + 1, stream->stream_size);
        !          1444:                                                /* flag as matched */
        !          1445:                                                matched = axl_true;
        !          1446:                                        } /* end if */
        !          1447:                                } /* end if */
        !          1448:                        } /* end if */
        !          1449:                        
        !          1450:                        /* check if we have found the chunk we were looking */
        !          1451:                        if (! matched) {
        !          1452:                                /* update iterator */
        !          1453:                                iterator ++;
        !          1454:                        }
        !          1455:                } /* end while */
        !          1456: 
        !          1457:                /* check that the function have found a chunk */
        !          1458:                if (matched) {
        !          1459:                        /* check for matching a more specific
        !          1460:                         * terminal than a general */
        !          1461:                        if ((length < max_length) && 
        !          1462:                            ((_index + length) == stream->stream_size)) {
        !          1463:                                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "detected possible false positive");
        !          1464:                                
        !          1465:                                /* do a prebuffer operation,
        !          1466:                                 * and if success, try to
        !          1467:                                 * check again all chunks at
        !          1468:                                 * the current index */
        !          1469:                                if (axl_stream_prebuffer (stream))
        !          1470:                                        goto init_get_until;
        !          1471:                        }
        !          1472: 
        !          1473:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "matched_chunk=%d", iterator);
        !          1474:                        
        !          1475:                        /* report which is the chunk being
        !          1476:                         * matched by the expresion */
        !          1477:                        stream->chunk_matched = iterator;
        !          1478: 
        !          1479:                matched_return_result:
        !          1480:                        
        !          1481:                        /* result is found from last stream
        !          1482:                         * index read up to index */
        !          1483:                        if (stream->last_chunk != NULL) {
        !          1484:                                axl_free (stream->last_chunk);
        !          1485:                                stream->last_chunk = NULL;
        !          1486:                        }
        !          1487:                        
        !          1488:                        /* get a copy to the chunk to be returned */
        !          1489:                        if (! stream->result_size) {
        !          1490:                                if (stream->alloc != NULL)
        !          1491:                                        stream->last_chunk = stream->alloc (index + 1, stream->alloc_data);
        !          1492:                                else 
        !          1493:                                        stream->last_chunk = axl_new (char, index + 1);
        !          1494:                                memcpy (stream->last_chunk, stream->stream + stream->stream_index, index);
        !          1495:                        }else {
        !          1496:                                /* *result_size = index;*/
        !          1497:                                stream->result_size = index;
        !          1498:                                string              = stream->stream + stream->stream_index;
        !          1499:                                
        !          1500:                                /* set a termination mark */
        !          1501:                                string [ index  ] = 0;
        !          1502:                                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG,
        !          1503:                                           "Nullify internally index=%d to avoid printf problems", index);
        !          1504:                        }
        !          1505:                        
        !          1506:                        /* in the case a memory chunk is being read */
        !          1507:                        if (stream->accept_terminator)
        !          1508:                                stream->stream_index     += length;
        !          1509:                        stream->stream_index             += index;
        !          1510:                        stream->global_index             += index;
        !          1511:                        stream->previous_inspect          = 0;
        !          1512:                        
        !          1513:                        
        !          1514:                        /* return allocated result */
        !          1515:                        if (! stream->result_size)
        !          1516:                                return stream->last_chunk;
        !          1517: 
        !          1518:                        /* return reference result */
        !          1519:                        return string;
        !          1520:                } /* end if */
        !          1521:                
        !          1522:                /* it seems that the chunk wasn't found */
        !          1523:                index++;
        !          1524: 
        !          1525:        }while (axl_true);
        !          1526: 
        !          1527:        /* return a NULL chunk. */
        !          1528:        return NULL;    
        !          1529: }
        !          1530: 
        !          1531: /** 
        !          1532:  * @brief Allows to perform the same operation like \ref
        !          1533:  * axl_stream_get_untilv but providing an already initialized and
        !          1534:  * opened std arg.
        !          1535:  *
        !          1536:  * This function is in fact, used by \ref axl_stream_get_untilv.
        !          1537:  * 
        !          1538:  * @param stream The stream where the operation will be peformed.
        !          1539:  * 
        !          1540:  * @param valid_chars The valid chars set to be used while reading
        !          1541:  * data.
        !          1542:  *
        !          1543:  * @param chunk_matched An optional value where the matched chunk will
        !          1544:  * be reported.
        !          1545:  *
        !          1546:  * @param accept_terminator Configure if terminator read should be
        !          1547:  * accepted or only the chunk read.
        !          1548:  *
        !          1549:  * @param result_size Allows to notify the caller with the chunk size
        !          1550:  * that is being returned by the function.
        !          1551:  *
        !          1552:  * @param chunk_num How many terminators are configured.
        !          1553:  *
        !          1554:  * @param args The list of terminators.
        !          1555:  * 
        !          1556:  * @return The chunk read or NULL if fails.
        !          1557:  */
        !          1558: char      * axl_stream_get_untilv      (axlStream * stream, 
        !          1559:                                        char      * valid_chars, 
        !          1560:                                        int       * chunk_matched,
        !          1561:                                        axl_bool    accept_terminator,
        !          1562:                                        int       * result_size,
        !          1563:                                        int         chunk_num, 
        !          1564:                                        va_list args)
        !          1565: {
        !          1566:        char * result;
        !          1567: 
        !          1568: 
        !          1569:        /* check max inspected chunks */
        !          1570:        if (chunk_num > MAX_INSPECTED_CHUNKS) {
        !          1571:                __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "unable to parse stream for the number of chunks to recognize. Max number supported is %d, but received %d",
        !          1572:                           MAX_INSPECTED_CHUNKS, stream->chunk_num);
        !          1573:                return NULL;
        !          1574:        }
        !          1575: 
        !          1576:        /* configure variables for the operation */
        !          1577:        stream->valid_chars       = valid_chars;
        !          1578:        stream->accept_terminator = accept_terminator;
        !          1579:        stream->result_size       = (result_size != NULL);
        !          1580:        stream->chunk_num         = chunk_num;
        !          1581: 
        !          1582:        /* call to current implementation */
        !          1583:        result = __axl_stream_get_untilv_wide (stream, args);
        !          1584: 
        !          1585:        /* check for returning references */
        !          1586:        if (result_size != NULL)
        !          1587:                *result_size   = stream->result_size;
        !          1588:        if (chunk_matched != NULL)
        !          1589:                *chunk_matched = stream->chunk_matched;
        !          1590: 
        !          1591:        /* return string matched */
        !          1592:        return result;
        !          1593: }
        !          1594: 
        !          1595: 
        !          1596: /** 
        !          1597:  * @brief Returns current index status for the given stream.
        !          1598:  *
        !          1599:  * This function could be used to get current index being read for the
        !          1600:  * stream received.
        !          1601:  * 
        !          1602:  * @param stream The stream where the index will be reported.
        !          1603:  * 
        !          1604:  * @return The index or -1 if fails.
        !          1605:  */
        !          1606: int         axl_stream_get_index       (axlStream * stream)
        !          1607: {
        !          1608:        axl_return_val_if_fail (stream, -1);
        !          1609: 
        !          1610:        return stream->stream_index;
        !          1611: }
        !          1612: 
        !          1613: /** 
        !          1614:  * @brief Returns current global index for the device being streamed.
        !          1615:  * 
        !          1616:  * @param stream The stream where the data is being requested.
        !          1617:  * 
        !          1618:  * @return The index or -1 if fails.
        !          1619:  */
        !          1620: int         axl_stream_get_global_index (axlStream * stream)
        !          1621: {
        !          1622:        axl_return_val_if_fail (stream, -1);
        !          1623: 
        !          1624:        return stream->global_index;
        !          1625: }
        !          1626: 
        !          1627: /** 
        !          1628:  * @brief Allows to get current stream size.
        !          1629:  * 
        !          1630:  * @param stream The stream where the stream size will be returned.
        !          1631:  * 
        !          1632:  * @return The stream size or -1 if fails. 
        !          1633:  */
        !          1634: int         axl_stream_get_size        (axlStream * stream)
        !          1635: {
        !          1636:        axl_return_val_if_fail (stream, -1);
        !          1637: 
        !          1638:        return stream->stream_size;
        !          1639: }
        !          1640: 
        !          1641: /** 
        !          1642:  * @brief Allows to get current status of the given stream, taking the
        !          1643:  * current index, getting an amount of <b>count</b> bytes before and
        !          1644:  * after the given index.
        !          1645:  *
        !          1646:  * This function is mainly used to get a piece of the stream at the
        !          1647:  * given position while reporting errors. This allows to show the
        !          1648:  * piece of xml that is failing.
        !          1649:  *
        !          1650:  * The string return must not be deallocated. Value returned is
        !          1651:  * actually managed by the stream object associated.
        !          1652:  * 
        !          1653:  * @param stream The stream where the near to operation will be performed.
        !          1654:  * @param count The amount of bytes to take.
        !          1655:  * 
        !          1656:  * @return A string that is taken counting bytes with provided
        !          1657:  * <b>count</b> value starting from the index. Stream provided must be
        !          1658:  * not NULL and count value must be greater than 0. 
        !          1659:  */
        !          1660: const char  * axl_stream_get_near_to     (axlStream * stream, int count)
        !          1661: {
        !          1662:        int first_index;
        !          1663:        int last_index;
        !          1664: 
        !          1665:        axl_return_val_if_fail (stream, NULL);
        !          1666:        axl_return_val_if_fail (count > 0, NULL);
        !          1667:        
        !          1668:        /* get first index */
        !          1669:        if ((stream->stream_index - count) <= 0)
        !          1670:                first_index = 0;
        !          1671:        else
        !          1672:                first_index = stream->stream_index - count;
        !          1673: 
        !          1674:        /* get last index */
        !          1675:        if ((stream->stream_index + count) >= (stream->stream_size - 1) )
        !          1676:                last_index  = (stream->stream_size) - first_index;
        !          1677:        else
        !          1678:                last_index  = (stream->stream_index + count) - first_index;
        !          1679: 
        !          1680:        /* release previous near to chunk */
        !          1681:        if (stream->last_near_to != NULL)
        !          1682:                axl_free (stream->last_near_to);
        !          1683: 
        !          1684:        stream->last_near_to = axl_new (char, last_index + 1);
        !          1685:        memcpy (stream->last_near_to, stream->stream + first_index, last_index);
        !          1686: 
        !          1687:        /* return current near to operation */
        !          1688:        return stream->last_near_to;
        !          1689:        
        !          1690: }
        !          1691: 
        !          1692: /** 
        !          1693:  * @brief Allows to get the following <b>count</b> bytes read from the
        !          1694:  * stream.
        !          1695:  * 
        !          1696:  * @param stream The stream where the operation will be performed.
        !          1697:  * @param count How many bytes to get from the stream.
        !          1698:  * 
        !          1699:  * @return A string referece, containing the first <b>count</b> bytes
        !          1700:  * or NULL if fails. Reference returned shouldn't be deallocated.
        !          1701:  */
        !          1702: const char  * axl_stream_get_following   (axlStream * stream, int count)
        !          1703: {
        !          1704:        axl_return_val_if_fail (stream, NULL);
        !          1705: 
        !          1706:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next characters from stream: index=%d size=%d",
        !          1707:                   stream->stream_index, stream->stream_size);
        !          1708: 
        !          1709:        /* check index */
        !          1710:        if (stream->stream_index >= stream->stream_size)
        !          1711:                return NULL;
        !          1712: 
        !          1713:        if ((count + stream->stream_index) > stream->stream_size) {
        !          1714:                count = stream->stream_size - stream->stream_index;
        !          1715:        }
        !          1716: 
        !          1717:        /* free previously allocated memory */
        !          1718:        if (stream->last_get_following != NULL)
        !          1719:                axl_free (stream->last_get_following);
        !          1720: 
        !          1721:        /* copy stream content */
        !          1722:        stream->last_get_following = axl_new (char, count + 1);
        !          1723:        memcpy (stream->last_get_following, stream->stream + stream->stream_index, count);
        !          1724: 
        !          1725:        /* return reference created */
        !          1726:        return stream->last_get_following;
        !          1727: }
        !          1728: 
        !          1729: typedef struct _AxlStreamAssociatedData {
        !          1730:        axlPointer       data;
        !          1731:        axlDestroyFunc   destroy_func;
        !          1732:        axl_bool         free_on_finish;
        !          1733: }AxlStreamAssociatedData;
        !          1734: 
        !          1735: 
        !          1736: /** 
        !          1737:  * @internal
        !          1738:  * 
        !          1739:  * Internal deallocation function to reclaim memory used by the \ref
        !          1740:  * AxlStreamAssociatedData.
        !          1741:  * 
        !          1742:  * @param data The data to be deallocated.
        !          1743:  */
        !          1744: void __stream_associated_data_free (AxlStreamAssociatedData * data)
        !          1745: {
        !          1746:        /* do nothing if NULL is received */
        !          1747:        if (data == NULL)
        !          1748:                return;
        !          1749: 
        !          1750:        /* destroy associated data used provided destroy function */
        !          1751:        if (data->destroy_func != NULL && data->data != NULL)
        !          1752:                data->destroy_func (data->data);
        !          1753: 
        !          1754:        /* now free the node it self */
        !          1755:        axl_free (data);
        !          1756: 
        !          1757:        return;
        !          1758: }
        !          1759: 
        !          1760: /** 
        !          1761:  * @brief Associates the given \ref axlPointer with the given stream to be
        !          1762:  * life-time dependant.
        !          1763:  *
        !          1764:  * While performing the XML parsing, errors will be produced. This
        !          1765:  * function ensures that the axlDoc document will be released if the
        !          1766:  * stream is also released.
        !          1767:  *
        !          1768:  * This not only reduces the possibility to produce a memory leak also
        !          1769:  * allows to write less code.
        !          1770:  *
        !          1771:  * Once the stream is not useful and it is required to be released,
        !          1772:  * but not doing so with the \ref axlDoc instance, a call to \ref
        !          1773:  * axl_stream_unlink is also required.
        !          1774:  * 
        !          1775:  * @param stream The axlStream where the document will be linked to.
        !          1776:  *
        !          1777:  * @param element The element to link (may a axlDoc or a axlDtd).
        !          1778:  *
        !          1779:  * @param func The function to call once the stream is released.
        !          1780:  */
        !          1781: void        axl_stream_link            (axlStream  *   stream,
        !          1782:                                        axlPointer     element,
        !          1783:                                        axlDestroyFunc func)
        !          1784: {
        !          1785:        /* call to base implementation */
        !          1786:        axl_stream_link_full (stream, element, func, axl_false);
        !          1787: 
        !          1788:        return;
        !          1789: }
        !          1790: 
        !          1791: /** 
        !          1792:  * @brief Allows to associate data references with a destroy function,
        !          1793:  * like \ref axl_stream_link, but ensuring the object reference will
        !          1794:  * be released once finished the axl stream, no mather if the
        !          1795:  * application code calls to \ref axl_stream_unlink.
        !          1796:  * 
        !          1797:  * @param stream The axlStream where the document will be linked to.
        !          1798:  *
        !          1799:  * @param element The element to link (may a axlDoc or a axlDtd).
        !          1800:  *
        !          1801:  *
        !          1802:  * @param func The function to call once the stream is released.
        !          1803:  *
        !          1804:  * @param free_on_finish axl_true to make the reference to be released on
        !          1805:  * \ref axlStream deallocation. Providing \ref axl_false to this value is
        !          1806:  * equivalent to call to \ref axl_stream_link directly.
        !          1807:  */
        !          1808: void       axl_stream_link_full     (axlStream  *   stream,
        !          1809:                                     axlPointer     element,
        !          1810:                                     axlDestroyFunc func,
        !          1811:                                     axl_bool       free_on_finish)
        !          1812: {
        !          1813:        AxlStreamAssociatedData * data;
        !          1814:        axl_return_if_fail (stream);
        !          1815:        axl_return_if_fail (element);
        !          1816:        axl_return_if_fail (func);
        !          1817:        
        !          1818:        /* that's all */
        !          1819:        if (stream->elements_linked == NULL)
        !          1820:                stream->elements_linked = axl_list_new (axl_list_always_return_1, 
        !          1821:                                                        (axlDestroyFunc) __stream_associated_data_free);
        !          1822: 
        !          1823:        /* create the data to be stored */
        !          1824:        data                 = axl_new (AxlStreamAssociatedData, 1);
        !          1825:        data->data           = element;
        !          1826:        data->destroy_func   = func;
        !          1827:        data->free_on_finish = free_on_finish;
        !          1828: 
        !          1829:        /* add the item to be destroy once the stream is unrefered */
        !          1830:        axl_list_add (stream->elements_linked, data);
        !          1831: 
        !          1832:        return;
        !          1833: }
        !          1834: 
        !          1835: /** 
        !          1836:  * @brief Unlinks the associated \ref axlDoc instance.
        !          1837:  * 
        !          1838:  * @param stream The stream where the operation will be performed.
        !          1839:  */
        !          1840: void axl_stream_unlink (axlStream * stream)
        !          1841: {
        !          1842:        int                       iterator;
        !          1843:        AxlStreamAssociatedData * data;
        !          1844: 
        !          1845:        axl_return_if_fail (stream);
        !          1846:        
        !          1847:        /* clear document association */
        !          1848:        iterator = 0;
        !          1849:        while (iterator < axl_list_length (stream->elements_linked)) {
        !          1850:                /* get a referece to the node to destroy */
        !          1851:                data = axl_list_get_nth (stream->elements_linked, iterator);
        !          1852:                /* clear it */
        !          1853:                if (! data->free_on_finish) {
        !          1854:                        data->data         = NULL;
        !          1855:                        data->destroy_func = NULL;
        !          1856:                }
        !          1857:                iterator++;
        !          1858:        }
        !          1859:        return;
        !          1860: }
        !          1861: 
        !          1862: /** 
        !          1863:  * @brief Allows to deallocate memory used by the \ref axlStream
        !          1864:  * received.
        !          1865:  * 
        !          1866:  * @param stream The stream to be deallocated.
        !          1867:  */
        !          1868: void axl_stream_free (axlStream * stream)
        !          1869: {
        !          1870:        axl_return_if_fail (stream);
        !          1871: 
        !          1872:        /* release memory */
        !          1873:        axl_free (stream->stream);
        !          1874: 
        !          1875:        /* release associated document is defined. */
        !          1876:        if (stream->elements_linked) 
        !          1877:                axl_list_free (stream->elements_linked);
        !          1878: 
        !          1879:        /* releaset last chunk */
        !          1880:        if (stream->last_chunk != NULL)
        !          1881:                axl_free (stream->last_chunk);
        !          1882: 
        !          1883:        /* releaset last near to */
        !          1884:        if (stream->last_near_to != NULL)
        !          1885:                axl_free (stream->last_near_to);
        !          1886: 
        !          1887:        /* releaset last get following */
        !          1888:        if (stream->last_get_following != NULL)
        !          1889:                axl_free (stream->last_get_following);
        !          1890: 
        !          1891:        if (stream->fd > 0) {
        !          1892:                /* close file descriptor if defined */
        !          1893:                close (stream->fd);
        !          1894:        }
        !          1895: 
        !          1896:        /* free memory allocated for chunk matching */
        !          1897:        axl_free (stream->chunks);
        !          1898: 
        !          1899:        /* free lengths */
        !          1900:        axl_free (stream->lengths);
        !          1901: 
        !          1902:        /* free temporal buffer */
        !          1903:        axl_free (stream->temp);
        !          1904:        axl_free (stream->decode_temp);
        !          1905:        axl_free (stream->source_encoding);
        !          1906: 
        !          1907:        /* release memory allocated by the stream received. */
        !          1908:        axl_free (stream);
        !          1909: 
        !          1910:        return;
        !          1911: }
        !          1912: 
        !          1913: 
        !          1914: /** 
        !          1915:  * @brief Allows to check if the given chunk is a white space in the
        !          1916:  * same of the XML 1.0 Third edition.
        !          1917:  *
        !          1918:  * The XML standard understand the "white space", also reffered as S,
        !          1919:  * as the following characters: \\x20 (the white space itself), \\n, \\r
        !          1920:  * and \\t.
        !          1921:  *
        !          1922:  * This function allows to check if the given chunk contains a white
        !          1923:  * space, in the previous sense.
        !          1924:  * 
        !          1925:  * @param chunk The chunk to check
        !          1926:  * 
        !          1927:  * @return axl_true if the chunk contains a white space or axl_false
        !          1928:  * if not.
        !          1929:  */
        !          1930: axl_bool        axl_stream_is_white_space  (char * chunk)
        !          1931: {
        !          1932:        /* do not complain about receive a null refernce chunk */
        !          1933:        if (chunk == NULL)
        !          1934:                return axl_false;
        !          1935:        
        !          1936:        if (chunk[0] == ' ')
        !          1937:                return axl_true;
        !          1938:        if (chunk[0] == '\n')
        !          1939:                return axl_true;
        !          1940:        if (chunk[0] == '\t')
        !          1941:                return axl_true;
        !          1942:        if (chunk[0] == '\r')
        !          1943:                return axl_true;
        !          1944: 
        !          1945:        /* no white space was found */
        !          1946:        return axl_false;
        !          1947: }
        !          1948: 
        !          1949: /** 
        !          1950:  * @brief Support function which consumes white spaces in the W3C
        !          1951:  * sense.
        !          1952:  * 
        !          1953:  * @param stream The stream where the operation will be performed.
        !          1954:  * 
        !          1955:  * @return axl_true if more white spaces could be consumed, axl_false
        !          1956:  * if not.
        !          1957:  */
        !          1958: void axl_stream_consume_white_spaces (axlStream * stream)
        !          1959: {
        !          1960:        /* get how many bytes remains to be read */
        !          1961:        int remains = stream->stream_size - stream->stream_index;
        !          1962: 
        !          1963:        while (axl_true) {
        !          1964:                /* decrase the number of bytes remaining to be read
        !          1965:                 * and check if it is zero or less than zero to
        !          1966:                 * prebuffer. NOTE: remains could be 1 (remains one
        !          1967:                 * byte) making it possible to consume one byte
        !          1968:                 * more */
        !          1969:                remains--;
        !          1970:                if (remains < 0) {
        !          1971:                        /* we fall outside the stream, so a prebuffer
        !          1972:                         * operation is required */
        !          1973:                        if (! axl_stream_prebuffer (stream))
        !          1974:                                return;
        !          1975:                        
        !          1976:                        /* update remains value but this time removing
        !          1977:                         * one unit (the unit to be consumed at the
        !          1978:                         * next sentence) */
        !          1979:                        remains = stream->stream_size - stream->stream_index - 1;
        !          1980:                 }
        !          1981:                
        !          1982:                /* check for a white space */
        !          1983:                if ((stream->stream[stream->stream_index] == ' ')  ||
        !          1984:                    (stream->stream[stream->stream_index] == '\n') ||
        !          1985:                    (stream->stream[stream->stream_index] == '\t') ||
        !          1986:                    (stream->stream[stream->stream_index] == '\r')) {
        !          1987: 
        !          1988:                        /* update internal indexes */
        !          1989:                        stream->stream_index++;
        !          1990:                        stream->global_index++;
        !          1991:                        stream->previous_inspect  = 0;
        !          1992:                }else {
        !          1993:                        /* return */
        !          1994:                        return;
        !          1995:                }
        !          1996:                
        !          1997:        } /* end while */
        !          1998: 
        !          1999:        return;
        !          2000: }
        !          2001: 
        !          2002: 
        !          2003: 
        !          2004: /** 
        !          2005:  * @internal
        !          2006:  * @brief Allows to compare two strings pointed by 
        !          2007:  * 
        !          2008:  * @param chunk1 The string to be compared.
        !          2009:  *
        !          2010:  * @param chunk2 The second string to be compared.
        !          2011:  *
        !          2012:  * @param size The amount of bytes to be compared for the two incoming
        !          2013:  * values.
        !          2014:  * 
        !          2015:  * @return axl_true if both string are equal, axl_false if not. If
        !          2016:  * some value provided is NULL or the size to compare is not greater
        !          2017:  * than 0 the function will return axl_false directly.
        !          2018:  */
        !          2019: axl_bool        axl_stream_cmp             (const char * chunk1, const char * chunk2, int size)
        !          2020: {
        !          2021:        /* perform some environmental condition checking */
        !          2022:        if (chunk1 == NULL)
        !          2023:                return axl_false;
        !          2024:        if (chunk2 == NULL)
        !          2025:                return axl_false;
        !          2026:        if (size < 0)
        !          2027:                return axl_false;
        !          2028:        
        !          2029:        /* report current comparation status */
        !          2030:        if ((chunk1[0] == chunk2[0])) {
        !          2031:                if ((size == 1) ||
        !          2032:                    (axl_memcmp (chunk1 + 1, chunk2 + 1, size -1))) {
        !          2033:                        return axl_true;
        !          2034:                } /* end if */
        !          2035:        } /* end if */
        !          2036: 
        !          2037:        return axl_false;
        !          2038: }
        !          2039: 
        !          2040: /** 
        !          2041:  * @brief Provides the same function like axl_stream_cmp but
        !          2042:  * ignoring the case of the characters (case insensitive manner).
        !          2043:  * 
        !          2044:  * @param chunk1 The string to be compared.
        !          2045:  *
        !          2046:  * @param chunk2 The second string to be compared.
        !          2047:  *
        !          2048:  * @param size The amount of bytes to be compared for the two incoming
        !          2049:  * values.
        !          2050:  * 
        !          2051:  * @return axl_true if both string are equal, axl_false if not. If
        !          2052:  * some value provided is NULL or the size to compare is not greater
        !          2053:  * than 0 the function will return axl_false directly.
        !          2054:  */
        !          2055: axl_bool        axl_stream_casecmp           (const char * chunk1, const char * chunk2, int size)
        !          2056: {
        !          2057:        /* perform some environmental condition checking */
        !          2058:        if (chunk1 == NULL)
        !          2059:                return axl_false;
        !          2060:        if (chunk2 == NULL)
        !          2061:                return axl_false;
        !          2062:        if (size < 0)
        !          2063:                return axl_false;
        !          2064: 
        !          2065:        /* returh if both strings are equal. */
        !          2066: #if defined(AXL_OS_WIN32)
        !          2067:        return _strnicmp (chunk1, chunk2, size) == 0;
        !          2068: #else
        !          2069:        return strncasecmp (chunk1, chunk2, size) == 0;
        !          2070: #endif
        !          2071: }
        !          2072: 
        !          2073: /** 
        !          2074:  * @internal
        !          2075:  *
        !          2076:  * @brief Allows to check if the provided stream could support
        !          2077:  * checking a chunk of, at least, the provided inspected size.
        !          2078:  * 
        !          2079:  * @param stream The stream where the inspected operation is being
        !          2080:  * requested.
        !          2081:  *
        !          2082:  * @param inspected_size The size to inspected, that is being
        !          2083:  * requested to be checked on the given stream.
        !          2084:  * 
        !          2085:  * @return \ref axl_true if the provided chunk falls out side the
        !          2086:  * stream boundaries, or axl_false if requested inspected size could
        !          2087:  * be supported.
        !          2088:  */
        !          2089: axl_bool axl_stream_fall_outside (axlStream * stream, int inspected_size)
        !          2090: {
        !          2091:        /* if the content is inside memory, check it */
        !          2092:        if (fall_out_side_checking (stream, inspected_size)) {
        !          2093:                return (! axl_stream_prebuffer (stream));
        !          2094:        }
        !          2095:        
        !          2096:        /* otherwise, axl_false is returned */
        !          2097:        return axl_false;
        !          2098: }
        !          2099: 
        !          2100: /** 
        !          2101:  * @internal
        !          2102:  *
        !          2103:  * @brief Allows to check if the given stream have as a next element
        !          2104:  * the provided chunk.
        !          2105:  * 
        !          2106:  * @param stream The stream where the operation will be performed.
        !          2107:  * @param chunk The chunk to check
        !          2108:  * 
        !          2109:  * @return Returns axl_true if the given stream contains the value requested
        !          2110:  * or axl_false if not.
        !          2111:  */
        !          2112: axl_bool         axl_stream_check           (axlStream * stream, char * chunk, int inspected_size)
        !          2113: {
        !          2114:        int iterator;
        !          2115: 
        !          2116:        /* call to the internal implementation of axl_memcmp */
        !          2117:        _memcmp(iterator,chunk,(stream->stream + stream->stream_index), inspected_size);
        !          2118: 
        !          2119: }
        !          2120: 
        !          2121: /** 
        !          2122:  * @brief Allows to get current status of the stream. 
        !          2123:  *
        !          2124:  * If the is exhausted and have no more data to be read.
        !          2125:  * 
        !          2126:  * @param stream The stream that is being checked.
        !          2127:  * 
        !          2128:  * @return axl_true if the stream is exhausted or axl_false if not.
        !          2129:  */
        !          2130: axl_bool        axl_stream_remains         (axlStream * stream)
        !          2131: {
        !          2132:        axl_return_val_if_fail (stream, axl_false);
        !          2133: 
        !          2134:        
        !          2135:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking for stream status with stream index=%d and stream size=%d",
        !          2136:                   stream->stream_index, stream->stream_size);
        !          2137:                
        !          2138:        /* check if the stream is exhausted */
        !          2139:        if (stream->stream_index >= (stream->stream_size)) {
        !          2140: 
        !          2141:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "prebufferring from remains");
        !          2142: 
        !          2143:                /* in the case the stream is exhausted, try to read
        !          2144:                 * more content from the streaming */
        !          2145:                return axl_stream_prebuffer (stream);
        !          2146:        }
        !          2147:        return axl_true;
        !          2148: }
        !          2149: 
        !          2150: 
        !          2151: /* @} */
        !          2152: 
        !          2153: /**
        !          2154:  * \defgroup axl_string_module Axl String: String functions provided by the Axl Stream module.
        !          2155:  */
        !          2156: 
        !          2157: /** 
        !          2158:  * \addtogroup axl_string_module
        !          2159:  * @{
        !          2160:  */
        !          2161: 
        !          2162: /** 
        !          2163:  *
        !          2164:  * @brief Allows to trim the provided chunk, removing all white spaces
        !          2165:  * (returns, white spaces, carry return and tabulars) that comes as
        !          2166:  * preffix and suffix for the string provided, referenced by chunk.
        !          2167:  *
        !          2168:  * The function retuns the reference to the new chunk already
        !          2169:  * translated. The function doesn't perform any memory allocation. It
        !          2170:  * uses the memory already used to hold the chunk provided, returning
        !          2171:  * a pointer for the first item that is not a white space and
        !          2172:  * nullifing the first item that is a white space behind the chunk.
        !          2173:  *
        !          2174:  * This function is particular useful while getting the content 
        !          2175:  * 
        !          2176:  * @param chunk The chunk to trim.
        !          2177:  *
        !          2178:  */
        !          2179: void      axl_stream_trim            (char * chunk)
        !          2180: {
        !          2181:        /* call to trim */
        !          2182:        axl_stream_trim_with_size (chunk, NULL);
        !          2183: 
        !          2184:        return;
        !          2185: }
        !          2186: 
        !          2187: /** 
        !          2188:  * @brief The function works like \ref axl_stream_trim, but providing
        !          2189:  * the count of bytes trimmed from the string.
        !          2190:  *
        !          2191:  * @param chunk The chunk to trim.
        !          2192:  *
        !          2193:  * @param trimmed An optional reference that returns the count of bytes
        !          2194:  * trimmed by the operation.
        !          2195:  */
        !          2196: void        axl_stream_trim_with_size  (char * chunk, int * trimmed)
        !          2197: {
        !          2198:        int    iterator;
        !          2199:        int    iterator2;
        !          2200:        int    end;
        !          2201:        int    total;
        !          2202: 
        !          2203:        /* perform some environment check */
        !          2204:        axl_return_if_fail (chunk);
        !          2205: 
        !          2206:        /* check empty string received */
        !          2207:        if (strlen (chunk) == 0) {
        !          2208:                if (trimmed)
        !          2209:                        *trimmed = 0;
        !          2210:                return;
        !          2211:        }
        !          2212: 
        !          2213:        /* check the amount of white spaces to remove from the
        !          2214:         * begin */
        !          2215:        iterator = 0;
        !          2216:        while (chunk[iterator] != 0) {
        !          2217:                
        !          2218:                /* check that the iterator is not pointing to a white
        !          2219:                 * space */
        !          2220:                if (! axl_stream_is_white_space (chunk + iterator))
        !          2221:                        break;
        !          2222:                
        !          2223:                /* update the iterator */
        !          2224:                iterator++;
        !          2225:        }
        !          2226: 
        !          2227:        /* check for the really basic case where an empty string is found */
        !          2228:        if (iterator == strlen (chunk)) {
        !          2229:                /* an empty string, trim it all */
        !          2230:                chunk [0] = 0;
        !          2231:                if (trimmed)
        !          2232:                        *trimmed = iterator;
        !          2233:                return;
        !          2234:        } /* end if */
        !          2235: 
        !          2236:        /* now get the position for the last valid character in the
        !          2237:         * chunk */
        !          2238:        total   = strlen (chunk) -1;
        !          2239:        end     = total;
        !          2240:        while (chunk[end] != 0) {
        !          2241:                
        !          2242:                /* stop if a white space is found */
        !          2243:                if (! axl_stream_is_white_space (chunk + end)) {
        !          2244:                        break;
        !          2245:                }
        !          2246: 
        !          2247:                /* update the iterator to eat the next white space */
        !          2248:                end--;
        !          2249:        }
        !          2250: 
        !          2251:        /* the number of items trimmed */
        !          2252:        total -= end;
        !          2253:        total += iterator;
        !          2254:        
        !          2255:        /* copy the exact amount of non white spaces items */
        !          2256:        iterator2 = 0;
        !          2257:        while (iterator2 < (end - iterator + 1)) {
        !          2258:                /* copy the content */
        !          2259:                chunk [iterator2] = chunk [iterator + iterator2];
        !          2260: 
        !          2261:                /* update the iterator */
        !          2262:                iterator2++;
        !          2263:        }
        !          2264:        chunk [ end - iterator + 1] = 0;
        !          2265: 
        !          2266:        if (trimmed != NULL)
        !          2267:                *trimmed = total;
        !          2268: 
        !          2269:        /* return the result reference */
        !          2270:        return; 
        !          2271: }
        !          2272: 
        !          2273: /** 
        !          2274:  * @brief Allows to remote occurences of value from the provided
        !          2275:  * string (chunk).
        !          2276:  *
        !          2277:  * The function do not allocate new memory for the result. All
        !          2278:  * operations are applied to the string received (chunk).
        !          2279:  *
        !          2280:  * The idea behind the functions is to allow removing values from the
        !          2281:  * string, joining remaining content. For example, removing "-" from
        !          2282:  * the string "iso-8859-15" yields "iso885915".
        !          2283:  * 
        !          2284:  * @param chunk The string that holds values to be removed.  
        !          2285:  *
        !          2286:  * @param value The value to be removed.
        !          2287:  *
        !          2288:  * @param first If only the first ocurrence of value must be removed,
        !          2289:  * otherwise all ocurrences will be removed from the string.
        !          2290:  */
        !          2291: void        axl_stream_remove            (char * chunk, const char * value, axl_bool first)
        !          2292: {
        !          2293:        int iterator;
        !          2294:        int iterator2;
        !          2295:        int length;
        !          2296:        int v_length;
        !          2297: 
        !          2298:        axl_return_if_fail (chunk);
        !          2299:        axl_return_if_fail (value);
        !          2300: 
        !          2301:        /* get lengths */
        !          2302:        length   = strlen (chunk);
        !          2303:        v_length = strlen (value);
        !          2304: 
        !          2305:        /* check for basic cases */
        !          2306:        if (length == v_length) {
        !          2307:                /* check if both strings are equal, then nullify */
        !          2308:                if (axl_cmp (chunk, value))
        !          2309:                        chunk [0] = 0;
        !          2310:                return;
        !          2311:        } else if (length < v_length) {
        !          2312:                /* nothing to remove because parent string is too
        !          2313:                 * small to store the content */
        !          2314:                return;
        !          2315:        } /* end if */
        !          2316:                
        !          2317: 
        !          2318:        /* locate the string */
        !          2319:        iterator = 0;
        !          2320:        while (iterator < length) {
        !          2321:                /* check if the string value was found */
        !          2322:                if (axl_memcmp (chunk + iterator, value, v_length)) {
        !          2323:                        /* string found, move content remaining (if is found) */
        !          2324:                        if ((length - iterator - v_length) > 0) {
        !          2325:                                iterator2 = 0;
        !          2326:                                while (iterator2 < (length - iterator - v_length)) {
        !          2327:                                        chunk [iterator + iterator2] = chunk [iterator + iterator2 + v_length];
        !          2328:                                        iterator2++;
        !          2329:                                } /* end while */
        !          2330:                        } /* end if */
        !          2331:                        
        !          2332:                        /* update length to the new value */
        !          2333:                        length -= v_length;
        !          2334: 
        !          2335:                        /* check to terminate for first ocurrence */
        !          2336:                        if (first) {
        !          2337:                                chunk [length] = 0;
        !          2338:                                return;
        !          2339:                        }
        !          2340:                        continue;
        !          2341:                } /* end if */
        !          2342: 
        !          2343:                /* next position */
        !          2344:                iterator++;
        !          2345:        } /* end while */
        !          2346: 
        !          2347:        /* nullify and terminate */
        !          2348:        chunk [length] = 0;
        !          2349:        return;
        !          2350: }
        !          2351: 
        !          2352: /** 
        !          2353:  * @brief Allows to copy the given chunk, supposing that is a properly
        !          2354:  * format C string that ends with a '\\0' value.
        !          2355:  *
        !          2356:  * This function allows to perform a copy for the given string. If a
        !          2357:  * copy limited by a size is required, use \ref axl_stream_strdup_n.
        !          2358:  * 
        !          2359:  * @param chunk The chunk to copy
        !          2360:  * 
        !          2361:  * @return A newly allocated string or NULL if fails.
        !          2362:  */
        !          2363: char      * axl_stream_strdup          (const char * chunk)
        !          2364: {
        !          2365:        char * result;
        !          2366:        int    length;
        !          2367: 
        !          2368:        /* return NULL reference if a NULL reference is received */
        !          2369:        if (chunk == NULL)
        !          2370:                return NULL;
        !          2371: 
        !          2372:        length = strlen (chunk);
        !          2373:        result = axl_new (char, length + 1);
        !          2374:        
        !          2375:        memcpy (result, chunk, length);
        !          2376: 
        !          2377:        return result;
        !          2378: }
        !          2379: 
        !          2380: /** 
        !          2381:  * @brief Allows to perform a copy for the <b>n</b> first bytes from
        !          2382:  * the <b>chunk</b> received.
        !          2383:  * 
        !          2384:  * @param chunk The chunk to copy
        !          2385:  *
        !          2386:  * @param n How many bytes to copy from the given chunk.
        !          2387:  * 
        !          2388:  * @return A newly allocated chunk, copied from the given chunk with a
        !          2389:  * size of <b>n</b> bytes. The function will check that the
        !          2390:  * <b>chunk</b> and the <b>n</b> values are not null and non-zero.
        !          2391:  */
        !          2392: char      * axl_stream_strdup_n (const char * chunk, int n)
        !          2393: {
        !          2394:        char * result;
        !          2395: 
        !          2396:        axl_return_val_if_fail (chunk, NULL);
        !          2397:        axl_return_val_if_fail (n, NULL);
        !          2398:        
        !          2399:        result = axl_new (char, n + 1);
        !          2400:        memcpy (result, chunk, n);
        !          2401:        
        !          2402:        return result;
        !          2403: }
        !          2404: 
        !          2405: /** 
        !          2406:  * @internal Allows to calculate the amount of memory required to
        !          2407:  * store the string that will representing the construction provided
        !          2408:  * by the printf-like format received and its arguments.
        !          2409:  * 
        !          2410:  * @param format The printf-like format to be printed.
        !          2411:  *
        !          2412:  * @param args The set of arguments that the printf applies to.
        !          2413:  *
        !          2414:  * <i><b>NOTE:</b> not all printf specification is supported. Generally, the
        !          2415:  * following is supported: %s, %d, %f, %g, %ld, %lg and all
        !          2416:  * combinations that provides precision, number of items inside the
        !          2417:  * integer part, etc: %6.2f, %+2d, etc. An especial case not supported
        !          2418:  * is %lld, %llu and %llg.</i>
        !          2419:  *
        !          2420:  * @return Return the number of bytes that must be allocated to hold
        !          2421:  * the string (including the string terminator \0). If the format is
        !          2422:  * not correct or it is not properly formated according to the value
        !          2423:  * found at the argument set, the function will return -1.
        !          2424:  */
        !          2425: int axl_stream_vprintf_len (const char * format, va_list args)
        !          2426: {
        !          2427: #if defined (AXL_OS_WIN32) && ! defined (__GNUC__)
        !          2428: #   if HAVE_VSCPRINTF
        !          2429:        if (format == NULL)
        !          2430:                return 0;
        !          2431:        return _vscprintf (format, args) + 1;
        !          2432: #   else
        !          2433:        char buffer[8192];
        !          2434:        if (format == NULL)
        !          2435:                return 0;
        !          2436:        return _vsnprintf (buffer, 8191, format, args) + 1;
        !          2437: #   endif
        !          2438: #else
        !          2439:        /* gnu gcc case */
        !          2440:        if (format == NULL)
        !          2441:                return 0;
        !          2442:        return vsnprintf (NULL, 0, format, args) + 1;
        !          2443: #endif
        !          2444: }
        !          2445: 
        !          2446: /** 
        !          2447:  * @brief Allows to perform a printf operation on the provided buffer
        !          2448:  * (which must be allocated by the caller, and its size signaled by
        !          2449:  * buffer_size).
        !          2450:  *
        !          2451:  *
        !          2452:  * @param buffer The already allocated buffer to hold the result.
        !          2453:  *
        !          2454:  * @param buffer_size The size of the buffer provided. 
        !          2455:  *
        !          2456:  * @param real_size Optional reference where the real space required
        !          2457:  * to hold the content will be placed. In cases where the content is
        !          2458:  * enough small to hold in the buffer, this value will contain the
        !          2459:  * same value as returned by the function. In the case the buffer
        !          2460:  * provide can't hold all the content, the function will return at
        !          2461:  * maximum (buffer_size - 1) bytes written, that is, all content that
        !          2462:  * was possible to be included plus a trailing \\0 to terminate the
        !          2463:  * string, and, if defined <i>real_size</i> variable, it will contain
        !          2464:  * the space that will be required.
        !          2465:  *
        !          2466:  * @param format The printf like format to use to create the content
        !          2467:  * to be placed at the buffer provided.
        !          2468:  *
        !          2469:  * @return The amount of bytes written. The function will return at
        !          2470:  * maximum buffer_size - 1 bytes written. Use <i>real_size</i>
        !          2471:  * variable to check if the function was able to write all content (if
        !          2472:  * real_size == value returned). 
        !          2473:  */
        !          2474: int axl_stream_printf_buffer (char * buffer, 
        !          2475:                              int    buffer_size, 
        !          2476:                              int  * real_size,
        !          2477:                              const char * format, ...)
        !          2478: {
        !          2479:        va_list args;
        !          2480:        int     result;
        !          2481: #if defined(AXL_OS_WIN32)
        !          2482:        int     check_size;
        !          2483: #endif 
        !          2484: 
        !          2485:        /* check foramt and optn */
        !          2486:        if (format == NULL) {
        !          2487:                /* clean real size if it was defined */
        !          2488:                if (real_size)
        !          2489:                        (*real_size) = 0;
        !          2490:                return 0;
        !          2491:        }
        !          2492:        /* open stdargs */
        !          2493:        va_start (args, format);
        !          2494: 
        !          2495: # if defined (AXL_OS_WIN32)
        !          2496:        /* because undre windows all its string family of functions
        !          2497:         * return -1 in the case not enough espace is available, we
        !          2498:         * have to check first before calling to _vsnprintf */
        !          2499:        check_size = axl_stream_vprintf_len (format, args);
        !          2500: 
        !          2501:        /* call to close to avoid problems with amd64 platforms */
        !          2502:        va_end (args);
        !          2503:        va_start (args, format);
        !          2504: 
        !          2505:        /* windows case */
        !          2506:        result = _vsnprintf (buffer, buffer_size, format, args);
        !          2507:        if (result == -1) {
        !          2508:                /* nullify last character and update "result" to point
        !          2509:                 * to the amount of data written (buffer - 1). */
        !          2510:                result = (buffer_size - 1);
        !          2511:                buffer[result] = 0; 
        !          2512:        } /* end if */
        !          2513: #else
        !          2514:        /* gnu gcc case */
        !          2515:        result = vsnprintf (buffer, buffer_size, format, args);
        !          2516: #endif
        !          2517:        /* close stdarg */
        !          2518:        va_end (args);
        !          2519: 
        !          2520:        /* report real size required */
        !          2521:        if (real_size) {
        !          2522: #if defined(AXL_OS_WIN32)
        !          2523:                (*real_size) = check_size - 1;
        !          2524: #else
        !          2525:                (*real_size) = result;
        !          2526: #endif
        !          2527:        } /* end if */
        !          2528: 
        !          2529:        /* limit result */
        !          2530:        if (result > (buffer_size - 1))
        !          2531:                result = (buffer_size - 1);
        !          2532: 
        !          2533:        return result;
        !          2534: }
        !          2535: 
        !          2536: /** 
        !          2537:  * @internal Function that allows to get how many bytes will be
        !          2538:  * required to hold the format and the arguments provided.
        !          2539:  * 
        !          2540:  * @param format The printf-like format followed by the rest of
        !          2541:  * arguments.
        !          2542:  * 
        !          2543:  * @return Return the number of bytes that must be allocated to hold
        !          2544:  * the string (including the string terminator \0). If the format is
        !          2545:  * not correct or it is not properly formated according to the value
        !          2546:  * found at the argument set, the function will return -1.
        !          2547:  */
        !          2548: int axl_stream_printf_len (const char * format, ...)
        !          2549: {
        !          2550:        int     result;
        !          2551:        va_list args;
        !          2552: 
        !          2553:        va_start (args, format);
        !          2554: 
        !          2555:        /* get the result */
        !          2556:        result = axl_stream_vprintf_len (format, args);
        !          2557:        
        !          2558:        va_end (args);
        !          2559: 
        !          2560:        return result;
        !          2561: }
        !          2562: 
        !          2563: 
        !          2564: /** 
        !          2565:  * @brief Allows to produce an newly allocated string produced by the
        !          2566:  * chunk received plus arguments, using the printf-like format.
        !          2567:  *
        !          2568:  * @param chunk The chunk to copy.
        !          2569:  * 
        !          2570:  * @return A newly allocated chunk.
        !          2571:  */
        !          2572: char      * axl_stream_strdup_printf   (const char * chunk, ...)
        !          2573: {
        !          2574:        char    * result   = NULL;
        !          2575:        va_list   args;
        !          2576:        
        !          2577:        axl_return_val_if_fail (chunk, NULL);
        !          2578: 
        !          2579:        /* open std args */
        !          2580:        va_start (args, chunk);
        !          2581: 
        !          2582:        /* get the string */
        !          2583:        result = axl_stream_strdup_printfv (chunk, args);
        !          2584:        
        !          2585:        /* close std args */
        !          2586:        va_end (args);
        !          2587:        
        !          2588:        return result;
        !          2589: }
        !          2590: 
        !          2591: /** 
        !          2592:  * @brief DEPRECATED: Allows to produce an string representing the
        !          2593:  * message hold by chunk with the parameters provided.
        !          2594:  * 
        !          2595:  * @param chunk The message chunk to print.
        !          2596:  * @param args The arguments for the chunk.
        !          2597:  * 
        !          2598:  * @return A newly allocated string.
        !          2599:  *
        !          2600:  * IMPLEMENTATION NOTE: This function have a fundamental bug due to
        !          2601:  * the design of va_list arguments under amd64 platforms. In short, a
        !          2602:  * function receiving a va_list argument can't use it twice. In you
        !          2603:  * are running amd64, check your axl_config.h did find
        !          2604:  * AXL_HAVE_VASPRINTF. 
        !          2605:  */
        !          2606: char  * axl_stream_strdup_printfv    (const char * chunk, va_list args)
        !          2607: {
        !          2608:        /** IMPLEMENTATION NOTE: place update exarg_strdup_printfv
        !          2609:         * code in the case this code is updated **/
        !          2610: 
        !          2611: #ifndef AXL_HAVE_VASPRINTF
        !          2612:        int       size;
        !          2613: #endif
        !          2614:        char    * result   = NULL;
        !          2615:        int       new_size = -1;
        !          2616: 
        !          2617:        axl_return_val_if_fail (chunk, NULL);
        !          2618: 
        !          2619: #ifdef AXL_HAVE_VASPRINTF
        !          2620:        /* do the operation using the GNU extension */
        !          2621:        new_size = vasprintf (&result, chunk, args);
        !          2622: #else
        !          2623:        /* get the amount of memory to be allocated */
        !          2624:        size = axl_stream_vprintf_len (chunk, args);
        !          2625: 
        !          2626:        /* check result */
        !          2627:        if (size == -1) {
        !          2628:                __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "unable to calculate the amount of memory for the strdup_printf operation");
        !          2629:                return NULL;
        !          2630:        } /* end if */
        !          2631: 
        !          2632:        /* allocate memory */
        !          2633:        result   = axl_new (char, size + 2);
        !          2634:        
        !          2635:        /* copy current size */
        !          2636: #    if defined(AXL_OS_WIN32) && ! defined (__GNUC__)
        !          2637:        new_size = _vsnprintf_s (result, size + 1, size, chunk, args);
        !          2638: #    else
        !          2639:        new_size = vsnprintf (result, size + 1, chunk, args);
        !          2640: #    endif
        !          2641: #endif
        !          2642:        /* return the result */
        !          2643:        return result;
        !          2644: }
        !          2645: 
        !          2646: /** 
        !          2647:  * @brief Allows to create a newly allocated chunk, providing its
        !          2648:  * values as a printf call function, but also returning the chunk
        !          2649:  * size.
        !          2650:  *
        !          2651:  * This function works like \ref axl_stream_strdup_printf, but
        !          2652:  * providing an integer reference where the result chunk length will
        !          2653:  * be returned. 
        !          2654:  * 
        !          2655:  * @param chunk The printf chunk format to allocate.
        !          2656:  *
        !          2657:  * @param chunk_size A reference to fill the chunk lenght.
        !          2658:  * 
        !          2659:  * @return A newly allocated chunk.
        !          2660:  */
        !          2661: char    * axl_stream_strdup_printf_len (const char * chunk, int * chunk_size, ...)
        !          2662: {
        !          2663: #ifndef AXL_HAVE_VASPRINTF
        !          2664:        int       size;
        !          2665: #endif
        !          2666:        int       new_size;
        !          2667:        char    * result;
        !          2668:        va_list   args;
        !          2669:        
        !          2670:        axl_return_val_if_fail (chunk, NULL);
        !          2671: 
        !          2672:        /* open std args */
        !          2673:        va_start (args, chunk_size);
        !          2674: 
        !          2675: #ifdef AXL_HAVE_VASPRINTF
        !          2676:        /* do the operation using the GNU extension */
        !          2677:        new_size = vasprintf (&result, chunk, args);
        !          2678: 
        !          2679:        /* reopen to avoid amd64 bug */
        !          2680:        va_end (args);
        !          2681:        va_start (args, chunk_size);
        !          2682: #else
        !          2683:        /* get the amount of memory to be allocated */
        !          2684:        size = axl_stream_vprintf_len (chunk, args);
        !          2685: 
        !          2686:        /* reopen to avoid amd64 bug */
        !          2687:        va_end (args);
        !          2688:        va_start (args, chunk_size);
        !          2689:        
        !          2690:        /* check result */
        !          2691:        if (size == -1) {
        !          2692:                __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "unable to calculate the amount of memory for the strdup_printf operation");
        !          2693:                return NULL;
        !          2694:        } /* end if */
        !          2695: 
        !          2696:        /* allocate memory */
        !          2697:        result   = axl_new (char, size + 2);
        !          2698: 
        !          2699:        /* copy current size */
        !          2700: #if defined(AXL_OS_WIN32) && ! defined (__GNUC__)
        !          2701:        new_size = _vsnprintf_s (result, size + 1, size, chunk, args);
        !          2702: #else
        !          2703:        new_size = vsnprintf (result, size + 1, chunk, args);
        !          2704: #endif
        !          2705: #endif
        !          2706:        
        !          2707:        /* close std args */
        !          2708:        va_end (args);
        !          2709: 
        !          2710:        /* fill the chunk size result */
        !          2711:        if (chunk_size != NULL)
        !          2712:                *chunk_size = new_size;
        !          2713: 
        !          2714:        return result;
        !          2715: }
        !          2716: 
        !          2717: /** 
        !          2718:  * @brief Allows to split the provided chunk, into several pieces that
        !          2719:  * are separated by the separator (or separators) provided.
        !          2720:  *
        !          2721:  * The function will try to split the chunk provide using the
        !          2722:  * separator provided, and optionally, all separators provided.
        !          2723:  *
        !          2724:  * Here is an example:
        !          2725:  * \code
        !          2726:  * char ** result;
        !          2727:  *
        !          2728:  * // split the provided value using the ':', ';' and ',' as separators.
        !          2729:  * result = axl_stream_split (value, 3, ":", ";", ",");
        !          2730:  * \endcode
        !          2731:  *
        !          2732:  * The value returned must be deallocated using \ref axl_stream_freev.
        !          2733:  *
        !          2734:  * @param chunk The chunk to split.
        !          2735:  *
        !          2736:  * @param separator_num The number os separators to be used while
        !          2737:  * spliting the chunk.
        !          2738:  * 
        !          2739:  * @return A newly allocated string, that must be deallocated by using
        !          2740:  * \ref axl_stream_freev. The function will return a NULL if the chunk
        !          2741:  * or the separators provided are NULL.
        !          2742:  *
        !          2743:  * NOTE: See also \ref axl_split.
        !          2744:  */
        !          2745: char     ** axl_stream_split           (const char * chunk, int separator_num, ...)
        !          2746: {
        !          2747:        va_list      args;
        !          2748:        char      ** separators;
        !          2749:        char      ** result;
        !          2750:        int          iterator;
        !          2751:        int          index;
        !          2752:        int          previous_index;
        !          2753:        int          count      = 0;
        !          2754:        int          length     = 0;
        !          2755: 
        !          2756:        /* check received values */
        !          2757:        axl_return_val_if_fail (chunk, NULL);
        !          2758:        axl_return_val_if_fail (separator_num > 0, NULL);
        !          2759: 
        !          2760:        separators = axl_new (char *, separator_num + 1);
        !          2761:        iterator   = 0;
        !          2762:        va_start (args, separator_num);
        !          2763: 
        !          2764:        /* get all separators to be used */
        !          2765:        while (iterator < separator_num) {
        !          2766:                separators[iterator] = va_arg (args, char *);
        !          2767:                iterator++;
        !          2768:        } /* end if */
        !          2769:        
        !          2770:        va_end (args);
        !          2771: 
        !          2772:        /* now, count the number of strings that we will get by
        !          2773:         * separating the string into several pieces */
        !          2774:        index    = 0;
        !          2775:        while (*(chunk + index) != 0) {
        !          2776: 
        !          2777:                /* reset the iterator */
        !          2778:                iterator = 0;
        !          2779:                while (iterator < separator_num) { 
        !          2780: 
        !          2781:                        /* compare the current index with the current
        !          2782:                         * separator */
        !          2783:                        length = strlen (separators[iterator]);
        !          2784:                        if (axl_memcmp (chunk + index, separators[iterator], length)) {
        !          2785: 
        !          2786:                                /* update items found */
        !          2787:                                count++;
        !          2788: 
        !          2789:                                /* update index to skip the item found */
        !          2790:                                index += length - 1; /* make the last index to be captured the the -1 */
        !          2791: 
        !          2792:                                /* break the loop */
        !          2793:                                break;
        !          2794:                        }
        !          2795:                        iterator++;
        !          2796:                }
        !          2797: 
        !          2798:                /* update the index to the next item */
        !          2799:                index++;
        !          2800:        } /* end if */
        !          2801:        
        !          2802:        /* create the result that will hold items separated */
        !          2803:        result = axl_new (char *, count + 2);
        !          2804: 
        !          2805:        /* now copy items found */
        !          2806:        count          = 0;
        !          2807:        index          = 0;
        !          2808: 
        !          2809:        /* remember previous_index */
        !          2810:        previous_index = index;
        !          2811:        while (*(chunk + index) != 0) {
        !          2812: 
        !          2813:                /* reset the iterator */
        !          2814:                iterator = 0;
        !          2815:                while (iterator < separator_num) { 
        !          2816: 
        !          2817:                        /* compare the current index with the current
        !          2818:                         * separator */
        !          2819:                        length = strlen (separators[iterator]);
        !          2820:                        if (axl_memcmp (chunk + index, separators[iterator], length)) {
        !          2821: 
        !          2822:                                /* copy the chunk found */
        !          2823:                                result[count] = axl_new (char, index - previous_index + 1);
        !          2824:                                memcpy (result[count], chunk + previous_index, index - previous_index);
        !          2825: 
        !          2826:                                /* axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "item found (last) '%s' (index=%d != previous=%d", result[count],  index, previous_index); */
        !          2827: 
        !          2828:                                /* update items found */
        !          2829:                                count++;
        !          2830: 
        !          2831:                                /* update index to skip the item found */
        !          2832:                                if (*(chunk + index + length) == 0) {
        !          2833:                                        /* in the case no more elements to read will be found */
        !          2834:                                        /* put an empty space at the end */
        !          2835:                                        result [count]    = axl_new (char, 1);
        !          2836:                                        
        !          2837:                                        axl_free (separators);
        !          2838:                                        return result;
        !          2839:                                }
        !          2840: 
        !          2841:                                /* remember previous_index */
        !          2842:                                index += length; 
        !          2843:                                previous_index = index;
        !          2844:                                index--; /* make the last index to be captured the the -1 */
        !          2845:                                break;
        !          2846:                        }
        !          2847:                        iterator++;
        !          2848:                }
        !          2849: 
        !          2850:                /* update the index to the next item */
        !          2851:                index++;
        !          2852:        }
        !          2853: 
        !          2854:        /* check for a last chunk */
        !          2855:        if (index != previous_index) {
        !          2856:                /* copy the chunk found */
        !          2857:                result[count] = axl_new (char, index - previous_index + 1);
        !          2858:                memcpy (result[count], chunk + previous_index, index - previous_index);
        !          2859: 
        !          2860:                /* axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "item found (last) '%s' (index=%d != previous=%d", result[count], index, previous_index); */
        !          2861:        }
        !          2862: 
        !          2863:        
        !          2864:        /* release memory */
        !          2865:        axl_free (separators);
        !          2866:        
        !          2867:        return result;
        !          2868: }
        !          2869: 
        !          2870: /** 
        !          2871:  * @brief Allows to clean an split created by \ref axl_stream_split by
        !          2872:  * removing all items found to be empty strings.
        !          2873:  * 
        !          2874:  * @param split The split to be updated by removing all empty string
        !          2875:  * items.
        !          2876:  *
        !          2877:  */
        !          2878: void        axl_stream_clean_split     (char ** split)
        !          2879: {
        !          2880:        int iterator;
        !          2881:        int iterator2;
        !          2882:        int iterator3;
        !          2883: 
        !          2884:        /* check input */
        !          2885:        axl_return_if_fail (split);
        !          2886: 
        !          2887:        /* remove empty strings */
        !          2888:        iterator = 0;
        !          2889:        while (split[iterator]) {
        !          2890:                if (strlen (split[iterator]) == 0) {
        !          2891: 
        !          2892:                        /* clear position joint */
        !          2893:                        axl_free (split[iterator]);
        !          2894:                        split[iterator] = NULL;
        !          2895: 
        !          2896:                        /* move strings */
        !          2897:                        iterator3 = 0;
        !          2898:                        iterator2 = iterator + 1;
        !          2899:                        while (split[iterator2 + iterator3]) {
        !          2900:                                /* move reference */
        !          2901:                                split[iterator + iterator3]  = split[iterator2 + iterator3];
        !          2902:                                
        !          2903:                                /* nullify */
        !          2904:                                split[iterator2 + iterator3] = NULL;
        !          2905:                                
        !          2906:                                /* next position */
        !          2907:                                iterator3++;
        !          2908:                        } /* end while */
        !          2909:                        continue;
        !          2910:                } /* end if */
        !          2911: 
        !          2912:                /* next iterator */
        !          2913:                iterator++;
        !          2914:        } /* end while */
        !          2915: 
        !          2916:        return;
        !          2917: }
        !          2918: 
        !          2919: /** 
        !          2920:  * @brief Allows to implement the oposite operation of \ref
        !          2921:  * axl_stream_split, by joing all strings provided inside the array
        !          2922:  * (strings), using as separator the value provided.
        !          2923:  * 
        !          2924:  * @param strings The set of strings to be joined.
        !          2925:  *
        !          2926:  * @param separator The separator to be used to join all strings
        !          2927:  * provided.
        !          2928:  *
        !          2929:  * 
        !          2930:  * @return A newly allocated reference, that must be release using
        !          2931:  * \ref axl_free.
        !          2932:  *
        !          2933:  * NOTE: See also \ref axl_join.
        !          2934:  */
        !          2935: char      * axl_stream_join            (char      ** strings, 
        !          2936:                                        const char * separator)
        !          2937: {
        !          2938:        int         length;
        !          2939:        int         sep_length;
        !          2940:        int         iterator;
        !          2941:        char      * result;
        !          2942:        axl_bool    next_sep;
        !          2943: 
        !          2944:        axl_return_val_if_fail (strings && strings[0], NULL);
        !          2945:        axl_return_val_if_fail (separator, NULL);
        !          2946: 
        !          2947:        /* get the amount of data to be allocated */
        !          2948:        length   = 0;
        !          2949:        iterator = 0;
        !          2950: 
        !          2951:        /* for each value to be joined */
        !          2952:        while (strings [iterator]) {
        !          2953:                /* count the number of bytes for each string */
        !          2954:                length += strlen (strings[iterator]);
        !          2955: 
        !          2956:                /* next iterator */
        !          2957:                iterator++;
        !          2958:        } /* end while */
        !          2959: 
        !          2960:        /* check for the basic case */
        !          2961:        if (iterator == 1) {
        !          2962:                /* only one piece is contained in the set of strings
        !          2963:                 * provided, so nothing can be joined */
        !          2964:                return axl_strdup (strings[0]);
        !          2965:        }
        !          2966:        
        !          2967:        /* add to the length the number of separatos to be added
        !          2968:         * (wihtout 1) and add a traling byte to terminate the
        !          2969:         * string */
        !          2970:        sep_length = strlen (separator);
        !          2971:        length    += (sep_length * (iterator - 1)) + 1;
        !          2972:        result     = axl_new (char, length);
        !          2973: 
        !          2974:        iterator   = 0;
        !          2975:        next_sep   = axl_false;
        !          2976:        length     = 0;
        !          2977: 
        !          2978:        while (strings [iterator]) {
        !          2979: 
        !          2980:                /* copy the content */
        !          2981:                if (next_sep) {
        !          2982:                        memcpy (result + length, separator, sep_length);
        !          2983: 
        !          2984:                        /* update the length */
        !          2985:                        length += sep_length;
        !          2986:                } else {
        !          2987:                        memcpy (result + length, strings[iterator], strlen (strings[iterator]));
        !          2988: 
        !          2989:                        /* update the length */
        !          2990:                        length += strlen (strings[iterator]);
        !          2991:                } /* end if */
        !          2992: 
        !          2993:                /* check if next is separator */
        !          2994:                next_sep = ! next_sep;
        !          2995: 
        !          2996:                /* update the iterator only if next value to be
        !          2997:                 * handled is a separator */
        !          2998:                if (next_sep) 
        !          2999:                        iterator++;
        !          3000:        } /* end while */
        !          3001: 
        !          3002:        /* return string created */
        !          3003:        return result;
        !          3004: }
        !          3005: 
        !          3006: /** 
        !          3007:  * @brief Allows to concatenate the two given strings into a single
        !          3008:  * one.
        !          3009:  *
        !          3010:  * The function will concatenate both string into a newly allocated
        !          3011:  * string that is the result of taking chunk1 followed by chunk2. 
        !          3012:  * 
        !          3013:  * If the function receive a NULL value for one of the string
        !          3014:  * received, the result from this function will be the other
        !          3015:  * string. This is done to support a common basic case where the
        !          3016:  * string provided for one of the arguments is the one being used two
        !          3017:  * hold an iterative result. This variable usually is NULL.
        !          3018:  *
        !          3019:  * Once the string returned is no longer needed, \ref axl_free must be
        !          3020:  * used to deallocate the result. 
        !          3021:  *
        !          3022:  * The function will use the strlen function to calculate current
        !          3023:  * chunk sizes to provide the result.
        !          3024:  *
        !          3025:  * 
        !          3026:  * @param chunk1 The first chunk to be placed on the result.
        !          3027:  *
        !          3028:  * @param chunk2 The second chunk to be placed on the result.
        !          3029:  * 
        !          3030:  * @return A newly allocated string, containing both strings, or NULL
        !          3031:  * if fails. The only way for this function to fail is to provide two
        !          3032:  * NULL references as incoming strings.
        !          3033:  *
        !          3034:  * NOTE: See also \ref axl_concat.
        !          3035:  */
        !          3036: char      * axl_stream_concat          (const char * chunk1, const char * chunk2)
        !          3037: {
        !          3038:        char * result;
        !          3039:        int    len1;
        !          3040:        int    len2;
        !          3041: 
        !          3042:        axl_return_val_if_fail ((chunk2 != NULL) || (chunk1 != NULL), NULL);
        !          3043: 
        !          3044:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "concat called..");
        !          3045: 
        !          3046:        if (chunk1 == NULL) {
        !          3047: 
        !          3048:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "concat called.., returning %s", chunk2);
        !          3049: 
        !          3050:                /* return the result */
        !          3051:                return axl_strdup (chunk2);
        !          3052:        }
        !          3053: 
        !          3054:        if (chunk2 == NULL) {
        !          3055: 
        !          3056:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "concat called.., returning %s", chunk1);
        !          3057: 
        !          3058:                /* return the result */
        !          3059:                return axl_strdup (chunk1);
        !          3060:        }
        !          3061: 
        !          3062:        /* return the concatenation */
        !          3063:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "concat called.., returning %s%s", chunk1, chunk2);
        !          3064: 
        !          3065:        /* alloc enough memory to hold both strings */
        !          3066:        len1 = strlen (chunk1);
        !          3067:        len2 = strlen (chunk2);
        !          3068:        result = axl_new (char, len1 + len2 + 1);
        !          3069: 
        !          3070:        /* copy the content */
        !          3071:        memcpy (result, chunk1, len1);
        !          3072:        memcpy (result + len1, chunk2, len2);
        !          3073: 
        !          3074:        /* return the string created */
        !          3075:        return result;
        !          3076: 
        !          3077: 
        !          3078: }
        !          3079: 
        !          3080: 
        !          3081: /** 
        !          3082:  * @brief Returns current number of items inside the chunks reference
        !          3083:  * provided.
        !          3084:  * 
        !          3085:  * @param chunks The chunks reference, which contains a list of
        !          3086:  * chunks.
        !          3087:  * 
        !          3088:  * @return The number of chunks that the reference has or -1 if it
        !          3089:  * fails.
        !          3090:  */
        !          3091: int         axl_stream_strv_num        (char ** chunks)
        !          3092: {
        !          3093:        int iterator = 0;
        !          3094: 
        !          3095:        axl_return_val_if_fail (chunks, -1);
        !          3096:        /* release memory used by all elements inside the chunk */
        !          3097:        while (chunks[iterator] != 0) {
        !          3098:                iterator++;
        !          3099:        }
        !          3100: 
        !          3101:        /* return current number of chunks */
        !          3102:        return iterator;
        !          3103:        
        !          3104: }
        !          3105: 
        !          3106: /** 
        !          3107:  * @brief Allows to release memory used by elements returned by \ref
        !          3108:  * axl_stream_split and other function that return a pointer to a char **.
        !          3109:  * 
        !          3110:  * @param chunks The chunk to release.
        !          3111:  */
        !          3112: void        axl_stream_freev           (char ** chunks)
        !          3113: {
        !          3114:        int iterator = 0;
        !          3115: 
        !          3116:        axl_return_if_fail (chunks);
        !          3117:         
        !          3118:        /* release memory used by all elements inside the chunk */
        !          3119:        while (chunks[iterator] != 0) {
        !          3120:                axl_free (chunks[iterator]);
        !          3121:                iterator++;
        !          3122:        }
        !          3123:        
        !          3124:        /* now release the chunk inside */
        !          3125:        axl_free (chunks);
        !          3126:        
        !          3127:        /* nothing more to do */
        !          3128:        return;
        !          3129: }
        !          3130: 
        !          3131: /** 
        !          3132:  * @internal 
        !          3133:  *
        !          3134:  * @brief Internal function to support \ref axl_stream_to_upper and
        !          3135:  * \ref axl_stream_to_lower
        !          3136:  * 
        !          3137:  * @param chunk The chunk to modify
        !          3138:  * @param desp Bits to increase.
        !          3139:  */
        !          3140: void __axl_stream_common_to (char * chunk, axl_bool to_upper)
        !          3141: {
        !          3142:        int iterator = 0;
        !          3143: 
        !          3144:        axl_return_if_fail (chunk);
        !          3145: 
        !          3146:        while (chunk[iterator] != 0) {
        !          3147:                /* change first ascii level */
        !          3148:                if (to_upper)
        !          3149:                        chunk[iterator] = toupper (chunk[iterator]);
        !          3150:                else
        !          3151:                        chunk[iterator] = tolower (chunk[iterator]);
        !          3152:                
        !          3153:                /* update iterators */
        !          3154:                iterator++;
        !          3155:        }       
        !          3156: 
        !          3157:        return;
        !          3158: }
        !          3159: 
        !          3160: /** 
        !          3161:  * @brief Makes the provided string to be converted to upper case
        !          3162:  * letters.
        !          3163:  *
        !          3164:  * The function will modify the address provided. If you want to get a
        !          3165:  * upper case copy for a particular string, copy it first, by using
        !          3166:  * \ref axl_strdup, and then use this function.
        !          3167:  *
        !          3168:  * The function, for convenience, will also return the string
        !          3169:  * reference received, already modified. This could be used while
        !          3170:  * using this function to convert parameters that are expected by
        !          3171:  * other functions.
        !          3172:  * 
        !          3173:  * @param chunk The chunk to upper case.
        !          3174:  */
        !          3175: char *    axl_stream_to_upper        (char  * chunk)
        !          3176: {
        !          3177:        __axl_stream_common_to (chunk, axl_true);
        !          3178:        return chunk;
        !          3179: }
        !          3180: 
        !          3181: /** 
        !          3182:  * @brief Allows to convert the provided string into lower cases
        !          3183:  * letter.
        !          3184:  *
        !          3185:  * The function, for convenience, will also return the string
        !          3186:  * reference received, already modified. This could be used while
        !          3187:  * using this function to convert parameters that are expected by
        !          3188:  * other functions.
        !          3189:  * 
        !          3190:  * @param chunk The chunk to lower case.
        !          3191:  */
        !          3192: char *     axl_stream_to_lower        (char  * chunk)
        !          3193: {
        !          3194:        __axl_stream_common_to (chunk, axl_false);
        !          3195:        return chunk;
        !          3196: }
        !          3197: 
        !          3198: /** 
        !          3199:  * @brief Allows to perform a to upper operation, like \ref
        !          3200:  * axl_stream_to_upper, but returning an new allocated reference.
        !          3201:  * 
        !          3202:  * @param chunk The string reference to upper.
        !          3203:  * 
        !          3204:  * @return A new reference allocated containing the result or NULL if
        !          3205:  * it fails.
        !          3206:  */
        !          3207: char      * axl_stream_to_upper_copy   (const char  * chunk)
        !          3208: {
        !          3209:        char * result;
        !          3210: 
        !          3211:        /* perform some environmental checks */
        !          3212:        axl_return_val_if_fail (chunk, NULL);
        !          3213: 
        !          3214:        /* make a copy */
        !          3215:        result = axl_strdup (chunk);
        !          3216: 
        !          3217:        /* upper it */
        !          3218:        __axl_stream_common_to (result, axl_true);
        !          3219: 
        !          3220:        /* return the result */
        !          3221:        return result;
        !          3222: }
        !          3223: 
        !          3224: 
        !          3225: /** 
        !          3226:  * @brief Allows to perform a to lower operation, like \ref
        !          3227:  * axl_stream_to_upper, but returning an new allocated reference.
        !          3228:  * 
        !          3229:  * @param chunk The string reference to lower.
        !          3230:  * 
        !          3231:  * @return A new reference allocated containing the result or NULL if
        !          3232:  * it fails.
        !          3233:  */
        !          3234: char      * axl_stream_to_lower_copy   (const char  * chunk)
        !          3235: {
        !          3236:        char * result;
        !          3237: 
        !          3238:        /* perform some environmental checks */
        !          3239:        axl_return_val_if_fail (chunk, NULL);
        !          3240: 
        !          3241:        /* make a copy */
        !          3242:        result = axl_strdup (chunk);
        !          3243: 
        !          3244:        /* lower it */
        !          3245:        __axl_stream_common_to (result, axl_false);
        !          3246: 
        !          3247:        /* return the result */
        !          3248:        return result;
        !          3249: }
        !          3250: 
        !          3251: /** 
        !          3252:  * @brief Allows to compare two strings provided, s1 and s1 to be
        !          3253:  * equal.
        !          3254:  *
        !          3255:  * In the case both are equal, \ref axl_true is returned. Otherwise \ref
        !          3256:  * axl_false. The function compares that both are equal not only by making
        !          3257:  * the first to be contained inside the second string. The check also
        !          3258:  * ensures that "test" isn't equal to "test1".
        !          3259:  *
        !          3260:  * @param string First string to check.
        !          3261:  *
        !          3262:  * @param string2 Second string to check.
        !          3263:  * 
        !          3264:  * @return \ref axl_true if both string are equal, otherwise \ref axl_false is
        !          3265:  * returned.
        !          3266:  */
        !          3267: axl_bool axl_cmp (const char * string, const char * string2)
        !          3268: {
        !          3269:        int iterator = 0;
        !          3270: 
        !          3271:        if (string == NULL)
        !          3272:                return axl_false;
        !          3273:        if (string2 == NULL)
        !          3274:                return axl_false;
        !          3275:        
        !          3276:        /* for each item inside the iterator */
        !          3277:        while (string [iterator] != 0 && string2 [iterator] != 0) {
        !          3278:                
        !          3279:                /* check the content */
        !          3280:                if (string [iterator] != string2 [iterator])
        !          3281:                        return axl_false;
        !          3282: 
        !          3283:                /* update the iterator */
        !          3284:                iterator++;
        !          3285:                
        !          3286:        } /* end while */
        !          3287:        
        !          3288:        /* check that both string ends at the same point */
        !          3289:        if (string [iterator] != 0 ||
        !          3290:            string2 [iterator] != 0)
        !          3291:                return axl_false;
        !          3292:        
        !          3293:        return axl_true;
        !          3294: }
        !          3295: 
        !          3296: axl_bool        axl_casecmp (const char * string, const char * string2)
        !          3297: {
        !          3298:        int length;
        !          3299: 
        !          3300:        if (string == NULL)
        !          3301:                return axl_false;
        !          3302:        if (string2 == NULL)
        !          3303:                return axl_false;
        !          3304: 
        !          3305:        /* get length associated to first string */
        !          3306:        length = strlen (string);
        !          3307:        if (length != strlen (string2))
        !          3308:                return axl_false;
        !          3309:        
        !          3310:        /* now check both lengths */
        !          3311:        return axl_stream_casecmp (string, string2, length);
        !          3312:        
        !          3313: }
        !          3314: 
        !          3315: 
        !          3316: /** 
        !          3317:  * @brief Allows to check if both strings provided are equal on its
        !          3318:  * initial size bytes.
        !          3319:  *
        !          3320:  * This function is more efficient than common memcmp because it
        !          3321:  * doesn't perform the additional work to figure out which are the
        !          3322:  * bytes that differ both strings.
        !          3323:  * 
        !          3324:  * @param string The string to check.
        !          3325:  *
        !          3326:  * @param string2 The second string to check.
        !          3327:  *
        !          3328:  * @param size The size to check for both strings to be equal.
        !          3329:  * 
        !          3330:  * @return \ref axl_true if the both strings are equal for its initial
        !          3331:  * size bytes or \ref axl_false if not.
        !          3332:  */
        !          3333: axl_bool axl_memcmp (const char * string, const char * string2, int size)
        !          3334: {
        !          3335:        int iterator = 0;
        !          3336: 
        !          3337:        _memcmp(iterator,string,string2,size);
        !          3338: }
        !          3339: 
        !          3340: /** 
        !          3341:  *
        !          3342:  * @brief Perform a memory copy from the string provided.
        !          3343:  * 
        !          3344:  * @param string The string to copy.
        !          3345:  * 
        !          3346:  * @return A newly allocated value or NULL if it fails. The value
        !          3347:  * returned, must be deallocated using \ref axl_free.
        !          3348:  */
        !          3349: char * axl_strdup (const char * string)
        !          3350: {
        !          3351:        return (string != NULL) ? (char *) axl_stream_strdup ((char *) string) : NULL;
        !          3352: }
        !          3353: 
        !          3354: /** 
        !          3355:  * @internal Function that handles decoding operations when decode
        !          3356:  * functions are defined.
        !          3357:  * 
        !          3358:  * @param stream The stream where the decode operation will be
        !          3359:  * performed. 
        !          3360:  *
        !          3361:  * @param error Optional \ref axlError reference where errors will be
        !          3362:  * reported.
        !          3363:  * 
        !          3364:  * @return axl_true if the operation was completed.
        !          3365:  */
        !          3366: axl_bool axl_stream_decode (axlStream  * stream, 
        !          3367:                        char       * output, 
        !          3368:                        int          output_max_size, 
        !          3369:                        int        * output_decoded, 
        !          3370:                        int        * op_result, 
        !          3371:                        axlError  ** error)
        !          3372: {
        !          3373: 
        !          3374:        int result;
        !          3375:        int size;
        !          3376: 
        !          3377:        /* clear op_result if defined */
        !          3378:        if (op_result)
        !          3379:                *op_result = 0;
        !          3380: 
        !          3381:        /* decode content from the stream directly */
        !          3382:        result = stream->decode_f (
        !          3383:                /* source */
        !          3384:                stream->decode_temp,
        !          3385:                /* source size */
        !          3386:                stream->decode_temp_last,
        !          3387:                /* source encoding: encode used by the source
        !          3388:                 * content provided */
        !          3389:                stream->source_encoding,
        !          3390:                /* output of content decoded and its size */
        !          3391:                output,
        !          3392:                /* output max size */
        !          3393:                output_max_size,
        !          3394:                /* output decoded */
        !          3395:                output_decoded,
        !          3396:                /* source remaining */
        !          3397:                &(stream->decode_temp_remain),
        !          3398:                /* user defined data */
        !          3399:                stream->decode_f_data);
        !          3400: 
        !          3401:        /* set op result if defined */
        !          3402:        if (op_result)
        !          3403:                *op_result = result;
        !          3404:        
        !          3405:        /* check result */
        !          3406:        if (result == 0) {
        !          3407:                __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "after decode operation result=%d, output_decoded (new buffer size)=%d (from %d original bytes)",
        !          3408:                           result, output_decoded ? *output_decoded : 0, stream->decode_temp_last);
        !          3409:                axl_error_new (-1, "found internal failure at decode operation, unable to complete entity parsing",
        !          3410:                               stream, error);
        !          3411:                return axl_false;
        !          3412:        } /* end if */
        !          3413:        
        !          3414:        __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "after decode operation result=%d, output_decoded (new buffer size)=%d",
        !          3415:                   result, output_decoded ? *output_decoded : 0);
        !          3416:        
        !          3417:        /* update axl stream internal state */
        !          3418:        if (result == 1) {
        !          3419:                /* then the conversión was complete a no data
        !          3420:                 * is pending the the temporal decode
        !          3421:                 * buffer */
        !          3422:                stream->decode_temp_index = 0;
        !          3423:                stream->decode_temp_last  = 0;
        !          3424:        } else if (result == 2) {
        !          3425:                /* not enough space was found at the destination
        !          3426:                 * buffer, pack content at the decode buffer at the
        !          3427:                 * next operation */
        !          3428:                size = stream->decode_temp_last - stream->decode_temp_remain;
        !          3429:                if (size <= 0) {
        !          3430:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, 
        !          3431:                                   "found decode function return 2 (signaling pending data to be decoded) but last - remain yields to %d",
        !          3432:                                   size);
        !          3433:                        axl_error_new (-1, "found decode function return 2 (signaling pending data to be decoded) but last - remain yields to 0 or less", NULL, error);
        !          3434:                        return axl_false;
        !          3435:                } /* end if */
        !          3436:                
        !          3437:                /* moving data */
        !          3438:                while (stream->decode_temp_index < size) { 
        !          3439:                        stream->decode_temp[stream->decode_temp_index] = stream->decode_temp[stream->decode_temp_remain +  stream->decode_temp_index];
        !          3440:                        stream->decode_temp_index++;
        !          3441:                } /* end while */
        !          3442:                
        !          3443:                /* now reset */
        !          3444:                stream->decode_temp_index = 0;
        !          3445:                stream->decode_temp_last  = size;
        !          3446:                
        !          3447:                /* reset to 1 since we have moved content to
        !          3448:                 * the begin of the buffer */
        !          3449:                result = 1;
        !          3450:        } /* end if */
        !          3451: 
        !          3452:        return (result == 1);
        !          3453: }
        !          3454: 
        !          3455: /** 
        !          3456:  * @internal Function used by the axl stream module to call to check
        !          3457:  * function defined.
        !          3458:  * 
        !          3459:  * @return axl_true if the check was fine, otherwise axl_false is returned.
        !          3460:  */
        !          3461: axl_bool axl_stream_content_check (axlStream * stream, const char * content, int content_length, axlError ** error)
        !          3462: {
        !          3463:        if (stream == NULL || content == NULL) {
        !          3464:                __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "content check function failed because null reference was received.");
        !          3465:                axl_error_new (-1, "content check function failed because null reference was received.", stream, error);
        !          3466:                return axl_false;
        !          3467:        } /* end if */
        !          3468:        
        !          3469:        /* return appropiate value */
        !          3470:        if (stream->check_f (content, content_length, stream->source_encoding, stream->check_f_data, error) == 1) 
        !          3471:                return axl_true;
        !          3472: 
        !          3473:        __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "content check function have failed");
        !          3474: 
        !          3475:        /* check if error reference was defined */
        !          3476:        return axl_false;
        !          3477: }
        !          3478: 
        !          3479: 
        !          3480: /** 
        !          3481:  * @internal Allows to configure a decode functions to be used to
        !          3482:  * translate content read into utf-8. 
        !          3483:  * 
        !          3484:  * @param stream The stream to be configured.
        !          3485:  *
        !          3486:  * @param source_encoding Original source encode.
        !          3487:  *
        !          3488:  * @param decode_f The function to be called to translate/check
        !          3489:  * content read into utf-8. If a null value is provided the decode
        !          3490:  * function is removed.
        !          3491:  *
        !          3492:  * @param error The reference where errors will be reported.
        !          3493:  *
        !          3494:  * @return axl_true if the function setup decode handler properly
        !          3495:  * otherwise axl_false is returned.
        !          3496:  */
        !          3497: axl_bool        axl_stream_setup_decode        (axlStream         * stream,
        !          3498:                                                const char        * source_encoding,
        !          3499:                                                axlStreamDecode     decode_f,
        !          3500:                                                axlPointer          user_data,
        !          3501:                                                axlError         ** error)
        !          3502: {
        !          3503:        axl_return_val_if_fail (stream, axl_false);
        !          3504: 
        !          3505:        /* do not check if the decode_f function is NULL (it's a valid
        !          3506:         * case) */
        !          3507:        stream->decode_f      = decode_f;
        !          3508:        stream->decode_f_data = user_data;
        !          3509: 
        !          3510:        /* store source encoding */
        !          3511:        if (source_encoding != NULL)
        !          3512:                stream->source_encoding = axl_strdup (source_encoding);
        !          3513: 
        !          3514:        /* call to check and decode if required bufferede content */
        !          3515:        if (stream->decode_f) {
        !          3516:                /* init decode buffer */
        !          3517:                stream->decode_temp_size = (stream->buffer_size * 2) + 1;
        !          3518:                stream->decode_temp      = axl_new (char, stream->decode_temp_size);
        !          3519: 
        !          3520:                /* move content into decode temporal buffer */
        !          3521:                memcpy (stream->decode_temp, 
        !          3522:                        stream->stream + stream->stream_index, 
        !          3523:                        stream->stream_size - stream->stream_index);
        !          3524:                stream->decode_temp_index = 0;
        !          3525:                stream->decode_temp_last  = stream->stream_size - stream->stream_index;
        !          3526:                __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "procesing %d bytes from decode buffer (total size: %d, current index: 0)", 
        !          3527:                           stream->decode_temp_last, stream->decode_temp_size);
        !          3528: 
        !          3529:                /* call to decode content */
        !          3530:                if (! axl_stream_decode (stream, 
        !          3531:                                         /* output */
        !          3532:                                         (stream->stream + stream->stream_index),
        !          3533:                                         /* output max size */
        !          3534:                                         stream->buffer_size - stream->stream_index,
        !          3535:                                         /* output decoded */
        !          3536:                                         &(stream->stream_size),
        !          3537:                                         /* do not define op result */
        !          3538:                                         NULL,
        !          3539:                                         error))
        !          3540:                        return axl_false;
        !          3541:                
        !          3542:                /* add to the stream size the current index */
        !          3543:                stream->stream_size += stream->stream_index;
        !          3544:                
        !          3545:        } /* end if */
        !          3546: 
        !          3547:        /* return result */
        !          3548:        return axl_true;
        !          3549: }
        !          3550: 
        !          3551: /** 
        !          3552:  * @brief Function that allows to configure a handler that is executed
        !          3553:  * to check content read into the axl stream buffer. See \ref
        !          3554:  * axlStreamContentCheck for more information.
        !          3555:  * 
        !          3556:  * @param stream The stream that is going to be configured.
        !          3557:  *
        !          3558:  * @param source_encoding The source encoding detected.
        !          3559:  *
        !          3560:  * @param check The function that implements the check.
        !          3561:  *
        !          3562:  * @param user_data User defined data to be passed to the check
        !          3563:  * function.
        !          3564:  *
        !          3565:  * @param error Optional \ref axlError reference where errors will be
        !          3566:  * reported.
        !          3567:  * 
        !          3568:  * @return The function returns axl_true if the cheker was installed and
        !          3569:  * first execution was completed.
        !          3570:  */
        !          3571: axl_bool    axl_stream_setup_check         (axlStream                * stream,
        !          3572:                                            const char               * source_encoding,
        !          3573:                                            axlStreamContentCheck      check,
        !          3574:                                            axlPointer                 user_data,
        !          3575:                                            axlError                ** error)
        !          3576: {
        !          3577:        axl_return_val_if_fail (stream, axl_false);
        !          3578: 
        !          3579:        /* do not check if the decode_f function is NULL (it's a valid
        !          3580:         * case) */
        !          3581:        stream->check_f      = check;
        !          3582:        stream->check_f_data = user_data;
        !          3583: 
        !          3584:        /* store source encoding */
        !          3585:        if (source_encoding != NULL) 
        !          3586:                stream->source_encoding = axl_strdup (source_encoding);
        !          3587: 
        !          3588:        if (stream->check_f) {
        !          3589:                /* call to check */
        !          3590:                if (! axl_stream_content_check (stream, stream->stream + stream->stream_index, stream->stream_size - stream->stream_index, error)) {
        !          3591:                        __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "content check function have failed, looks like there is a problem with content");
        !          3592:                        return axl_false;
        !          3593:                } /* end if */
        !          3594:        } /* end if */
        !          3595: 
        !          3596:        return axl_true;
        !          3597: }
        !          3598: 
        !          3599: /* @} */
        !          3600: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>