Annotation of gpl/axl/src/axl_stream.c, revision 1.1.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>