Annotation of embedaddon/libpdel/structs/type/structs_type_array.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (c) 2001-2002 Packet Design, LLC.
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Subject to the following obligations and disclaimer of warranty,
                      7:  * use and redistribution of this software, in source or object code
                      8:  * forms, with or without modifications are expressly permitted by
                      9:  * Packet Design; provided, however, that:
                     10:  * 
                     11:  *    (i)  Any and all reproductions of the source or object code
                     12:  *         must include the copyright notice above and the following
                     13:  *         disclaimer of warranties; and
                     14:  *    (ii) No rights are granted, in any manner or form, to use
                     15:  *         Packet Design trademarks, including the mark "PACKET DESIGN"
                     16:  *         on advertising, endorsements, or otherwise except as such
                     17:  *         appears in the above copyright notice or in the software.
                     18:  * 
                     19:  * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
                     20:  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
                     21:  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
                     22:  * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
                     23:  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
                     24:  * OR NON-INFRINGEMENT.  PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
                     25:  * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
                     26:  * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
                     27:  * RELIABILITY OR OTHERWISE.  IN NO EVENT SHALL PACKET DESIGN BE
                     28:  * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
                     29:  * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
                     30:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
                     31:  * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
                     32:  * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
                     33:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     34:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
                     35:  * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
                     36:  * THE POSSIBILITY OF SUCH DAMAGE.
                     37:  *
                     38:  * Author: Archie Cobbs <archie@freebsd.org>
                     39:  */
                     40: 
                     41: #include <sys/types.h>
                     42: #include <sys/param.h>
                     43: #include <netinet/in.h>
                     44: #include <arpa/inet.h>
                     45: 
                     46: #include <stdio.h>
                     47: #include <stdlib.h>
                     48: #include <stdarg.h>
                     49: #include <string.h>
                     50: #include <errno.h>
                     51: 
                     52: #include "structs/structs.h"
                     53: #include "structs/type/array.h"
                     54: #include "util/typed_mem.h"
                     55: 
                     56: #define NUM_BYTES(x)   (((x) + 7) / 8)
                     57: 
                     58: /*********************************************************************
                     59:                        ARRAY TYPES
                     60: *********************************************************************/
                     61: 
                     62: int
                     63: structs_array_copy(const struct structs_type *type,
                     64:        const void *from, void *to)
                     65: {
                     66:        const struct structs_type *const etype = type->args[0].v;
                     67:        const char *mtype = type->args[1].v;
                     68:        const struct structs_array *const fary = from;
                     69:        struct structs_array *const tary = to;
                     70:        int errno_save;
                     71:        u_int i;
                     72: 
                     73:        /* Make sure it's really an array type */
                     74:        if (type->tclass != STRUCTS_TYPE_ARRAY) {
                     75:                errno = EINVAL;
                     76:                return (-1);
                     77:        }
                     78: 
                     79:        /* Allocate a new array */
                     80:        memset(tary, 0, sizeof(*tary));
                     81:        if ((tary->elems = MALLOC(mtype,
                     82:            fary->length * etype->size)) == NULL)
                     83:                return (-1);
                     84: 
                     85:        /* Copy elements into it */
                     86:        for (i = 0; i < fary->length; i++) {
                     87:                const void *const from_elem
                     88:                    = (char *)fary->elems + (i * etype->size);
                     89:                void *const to_elem = (char *)tary->elems + (i * etype->size);
                     90: 
                     91:                if ((*etype->copy)(etype, from_elem, to_elem) == -1)
                     92:                        break;
                     93:                tary->length++;
                     94:        }
                     95: 
                     96:        /* If there was a failure, undo the half completed job */
                     97:        if (i < fary->length) {
                     98:                errno_save = errno;
                     99:                while (i-- > 0) {
                    100:                        (*etype->uninit)(etype,
                    101:                            (char *)tary->elems + (i * etype->size));
                    102:                }
                    103:                FREE(mtype, tary->elems);
                    104:                memset(tary, 0, sizeof(*tary));
                    105:                errno = errno_save;
                    106:                return (-1);
                    107:        }
                    108: 
                    109:        /* Done */
                    110:        return (0);
                    111: }
                    112: 
                    113: int
                    114: structs_array_equal(const struct structs_type *type,
                    115:        const void *v1, const void *v2)
                    116: {
                    117:        const struct structs_type *const etype = type->args[0].v;
                    118:        const struct structs_array *const ary1 = v1;
                    119:        const struct structs_array *const ary2 = v2;
                    120:        u_int i;
                    121: 
                    122:        /* Make sure it's really an array type */
                    123:        if (type->tclass != STRUCTS_TYPE_ARRAY)
                    124:                return (0);
                    125: 
                    126:        /* Check array lengths first */
                    127:        if (ary1->length != ary2->length)
                    128:                return (0);
                    129: 
                    130:        /* Now compare individual elements */
                    131:        for (i = 0;
                    132:            i < ary1->length && (*etype->equal)(etype,
                    133:                (char *)ary1->elems + (i * etype->size),
                    134:                (char *)ary2->elems + (i * etype->size));
                    135:            i++);
                    136:        return (i == ary1->length);
                    137: }
                    138: 
                    139: int
                    140: structs_array_encode(const struct structs_type *type, const char *mtype,
                    141:        struct structs_data *code, const void *data)
                    142: {
                    143:        const struct structs_type *const etype = type->args[0].v;
                    144:        const struct structs_array *const ary = data;
                    145:        const u_int bitslen = NUM_BYTES(ary->length);
                    146:        struct structs_data *ecodes;
                    147:        u_int32_t elength;
                    148:        u_char *bits;
                    149:        void *delem;
                    150:        u_int tlen;
                    151:        int r = -1;
                    152:        u_int i;
                    153: 
                    154:        /* Make sure it's really an array type */
                    155:        if (type->tclass != STRUCTS_TYPE_ARRAY) {
                    156:                errno = EINVAL;
                    157:                return (-1);
                    158:        }
                    159: 
                    160:        /* Get the default value for an element */
                    161:        if ((delem = MALLOC(TYPED_MEM_TEMP, etype->size)) == NULL)
                    162:                return (-1);
                    163:        if (structs_init(etype, NULL, delem) == -1)
                    164:                goto fail1;
                    165: 
                    166:        /* Create bit array. Each bit indicates an element that is present. */
                    167:        if ((bits = MALLOC(TYPED_MEM_TEMP, bitslen)) == NULL)
                    168:                goto fail2;
                    169:        memset(bits, 0, bitslen);
                    170:        tlen = 4 + bitslen;                     /* length word + bits array */
                    171: 
                    172:        /* Create array of individual encodings, one per element */
                    173:        if ((ecodes = MALLOC(TYPED_MEM_TEMP,
                    174:            ary->length * sizeof(*ecodes))) == NULL)
                    175:                goto fail3;
                    176:        for (i = 0; i < ary->length; i++) {
                    177:                const void *const elem = (char *)ary->elems + (i * etype->size);
                    178:                struct structs_data *const ecode = &ecodes[i];
                    179: 
                    180:                /* Check for default value, leave out if same as */
                    181:                if ((*etype->equal)(etype, elem, delem) == 1) {
                    182:                        memset(ecode, 0, sizeof(*ecode));
                    183:                        continue;
                    184:                }
                    185:                bits[i / 8] |= (1 << (i % 8));
                    186: 
                    187:                /* Encode element */
                    188:                if ((*etype->encode)(etype, TYPED_MEM_TEMP, ecode, elem) == -1)
                    189:                        goto fail4;
                    190:                tlen += ecode->length;
                    191:        }
                    192: 
                    193:        /* Allocate final encoded region */
                    194:        if ((code->data = MALLOC(mtype, tlen)) == NULL)
                    195:                goto fail4;
                    196: 
                    197:        /* Copy array length */
                    198:        elength = htonl(ary->length);
                    199:        memcpy(code->data, &elength, 4);
                    200:        code->length = 4;
                    201: 
                    202:        /* Copy bits array */
                    203:        memcpy(code->data + code->length, bits, bitslen);
                    204:        code->length += bitslen;
                    205: 
                    206:        /* Copy encoded elements */
                    207:        for (i = 0; i < ary->length; i++) {
                    208:                struct structs_data *const ecode = &ecodes[i];
                    209: 
                    210:                memcpy(code->data + code->length, ecode->data, ecode->length);
                    211:                code->length += ecode->length;
                    212:        }
                    213: 
                    214:        /* OK */
                    215:        r = 0;
                    216: 
                    217:        /* Clean up and exit */
                    218: fail4: while (i-- > 0)
                    219:                FREE(TYPED_MEM_TEMP, ecodes[i].data);
                    220:        FREE(TYPED_MEM_TEMP, ecodes);
                    221: fail3: FREE(TYPED_MEM_TEMP, bits);
                    222: fail2: structs_free(etype, NULL, delem);
                    223: fail1: FREE(TYPED_MEM_TEMP, delem);
                    224:        return (r);
                    225: }
                    226: 
                    227: int
                    228: structs_array_decode(const struct structs_type *type, const u_char *code,
                    229:        size_t cmax, void *data, char *ebuf, size_t emax)
                    230: {
                    231:        const struct structs_type *const etype = type->args[0].v;
                    232:        const char *const mtype = type->args[1].v;
                    233:        struct structs_array *const ary = data;
                    234:        const u_char *bits;
                    235:        u_int32_t elength;
                    236:        u_int bitslen;
                    237:        int clen;
                    238:        u_int i;
                    239: 
                    240:        /* Make sure it's really an array type */
                    241:        if (type->tclass != STRUCTS_TYPE_ARRAY) {
                    242:                errno = EINVAL;
                    243:                return (-1);
                    244:        }
                    245: 
                    246:        /* Get number of elements */
                    247:        if (cmax < 4)
                    248:                goto truncated;
                    249:        memcpy(&elength, code, 4);
                    250:        ary->length = ntohl(elength);
                    251:        code += 4;
                    252:        cmax -= 4;
                    253:        clen = 4;
                    254: 
                    255:        /* Get bits array */
                    256:        bitslen = NUM_BYTES(ary->length);
                    257:        if (cmax < bitslen) {
                    258: truncated:     strlcpy(ebuf, "encoded array is truncated", emax);
                    259:                errno = EINVAL;
                    260:                return (-1);
                    261:        }
                    262:        bits = code;
                    263:        code += bitslen;
                    264:        cmax -= bitslen;
                    265:        clen += bitslen;
                    266: 
                    267:        /* Allocate array elements */
                    268:        if ((ary->elems = MALLOC(mtype, ary->length * etype->size)) == NULL)
                    269:                return (-1);
                    270: 
                    271:        /* Decode elements */
                    272:        for (i = 0; i < ary->length; i++) {
                    273:                void *const edata = (char *)ary->elems + (i * etype->size);
                    274:                int eclen;
                    275: 
                    276:                /* If element not present, assign it the default value */
                    277:                if ((bits[i / 8] & (1 << (i % 8))) == 0) {
                    278:                        if (structs_init(etype, NULL, edata) == -1)
                    279:                                goto fail;
                    280:                        continue;
                    281:                }
                    282: 
                    283:                /* Decode element */
                    284:                if ((eclen = (*etype->decode)(etype,
                    285:                    code, cmax, edata, ebuf, emax)) == -1)
                    286:                        goto fail;
                    287: 
                    288:                /* Go to next encoded element */
                    289:                code += eclen;
                    290:                cmax -= eclen;
                    291:                clen += eclen;
                    292:                continue;
                    293: 
                    294:                /* Un-do work done so far */
                    295: fail:          while (i-- > 0) {
                    296:                        structs_free(etype, NULL,
                    297:                            (char *)ary->elems + (i * etype->size));
                    298:                }
                    299:                FREE(mtype, ary->elems);
                    300:                return (-1);
                    301:        }
                    302: 
                    303:        /* Done */
                    304:        return (clen);
                    305: }
                    306: 
                    307: void
                    308: structs_array_free(const struct structs_type *type, void *data)
                    309: {
                    310:        const struct structs_type *const etype = type->args[0].v;
                    311:        const char *mtype = type->args[1].v;
                    312:        struct structs_array *const ary = data;
                    313:        u_int i;
                    314: 
                    315:        /* Make sure it's really an array type */
                    316:        if (type->tclass != STRUCTS_TYPE_ARRAY)
                    317:                return;
                    318: 
                    319:        /* Free individual elements */
                    320:        for (i = 0; i < ary->length; i++)
                    321:                (*etype->uninit)(etype, (char *)ary->elems + (i * etype->size));
                    322: 
                    323:        /* Free array itself */
                    324:        FREE(mtype, ary->elems);
                    325:        memset(ary, 0, sizeof(*ary));
                    326: }
                    327: 
                    328: int
                    329: structs_array_length(const struct structs_type *type,
                    330:        const char *name, const void *data)
                    331: {
                    332:        const struct structs_array *ary = data;
                    333: 
                    334:        /* Find array */
                    335:        if ((type = structs_find(type, name, (void **)&ary, 0)) == NULL)
                    336:                return (-1);
                    337: 
                    338:        /* Make sure it's really an array type */
                    339:        if (type->tclass != STRUCTS_TYPE_ARRAY) {
                    340:                errno = EINVAL;
                    341:                return (-1);
                    342:        }
                    343: 
                    344:        /* Return length */
                    345:        return (ary->length);
                    346: }
                    347: 
                    348: int
                    349: structs_array_reset(const struct structs_type *type,
                    350:        const char *name, void *data)
                    351: {
                    352:        /* Find array */
                    353:        if ((type = structs_find(type, name, &data, 1)) == NULL)
                    354:                return (-1);
                    355: 
                    356:        /* Make sure it's really an array type */
                    357:        if (type->tclass != STRUCTS_TYPE_ARRAY) {
                    358:                errno = EINVAL;
                    359:                return (-1);
                    360:        }
                    361: 
                    362:        /* Free it, which resets it as well */
                    363:        structs_array_free(type, data);
                    364:        return (0);
                    365: }
                    366: 
                    367: int
                    368: structs_array_insert(const struct structs_type *type,
                    369:        const char *name, u_int index, void *data)
                    370: {
                    371:        struct structs_array *ary = data;
                    372:        const struct structs_type *etype;
                    373:        const char *mtype;
                    374:        void *mem;
                    375: 
                    376:        /* Find array */
                    377:        if ((type = structs_find(type, name, (void **)&ary, 0)) == NULL)
                    378:                return (-1);
                    379:        etype = type->args[0].v;
                    380:        mtype = type->args[1].v;
                    381: 
                    382:        /* Make sure it's really an array type */
                    383:        if (type->tclass != STRUCTS_TYPE_ARRAY) {
                    384:                errno = EINVAL;
                    385:                return (-1);
                    386:        }
                    387: 
                    388:        /* Check index */
                    389:        if (index > ary->length) {
                    390:                errno = EDOM;
                    391:                return (-1);
                    392:        }
                    393: 
                    394:        /* Reallocate array, leaving room for new element and a shift */
                    395:        if ((mem = REALLOC(mtype,
                    396:            ary->elems, (ary->length + 2) * etype->size)) == NULL)
                    397:                return (-1);
                    398:        ary->elems = mem;
                    399: 
                    400:        /* Initialize new element; we'll move it into place later */
                    401:        if ((*etype->init)(etype,
                    402:            (char *)ary->elems + (ary->length + 1) * etype->size) == -1)
                    403:                return (-1);
                    404: 
                    405:        /* Shift array over by one and move new element into place */
                    406:        memmove((char *)ary->elems + (index + 1) * etype->size,
                    407:            (char *)ary->elems + index * etype->size,
                    408:            (ary->length - index) * etype->size);
                    409:        memcpy((char *)ary->elems + index * etype->size,
                    410:            (char *)ary->elems + (ary->length + 1) * etype->size, etype->size);
                    411:        ary->length++;
                    412:        return (0);
                    413: }
                    414: 
                    415: int
                    416: structs_array_delete(const struct structs_type *type,
                    417:        const char *name, u_int index, void *data)
                    418: {
                    419:        const struct structs_type *etype;
                    420:        struct structs_array *ary = data;
                    421: 
                    422:        /* Find array */
                    423:        if ((type = structs_find(type, name, (void **)&ary, 0)) == NULL)
                    424:                return (-1);
                    425:        etype = type->args[0].v;
                    426: 
                    427:        /* Make sure it's really an array type */
                    428:        if (type->tclass != STRUCTS_TYPE_ARRAY) {
                    429:                errno = EINVAL;
                    430:                return (-1);
                    431:        }
                    432: 
                    433:        /* Check index */
                    434:        if (index >= ary->length) {
                    435:                errno = EDOM;
                    436:                return (-1);
                    437:        }
                    438: 
                    439:        /* Free element */
                    440:        (*etype->uninit)(etype, (char *)ary->elems + (index * etype->size));
                    441: 
                    442:        /* Shift array */
                    443:        memmove((char *)ary->elems + index * etype->size,
                    444:            (char *)ary->elems + (index + 1) * etype->size,
                    445:            (--ary->length - index) * etype->size);
                    446:        return (0);
                    447: }
                    448: 
                    449: /*
                    450:  * Given a name, prepare all arrays in the name path for being
                    451:  * set with a new element.
                    452:  *
                    453:  * This means that any array index equal to the length of the array
                    454:  * causes a new element to be appended to the array rather than
                    455:  * an element not found error, and that any array index equal to
                    456:  * zero means to reset the entire array to be empty.
                    457:  *
                    458:  * This allows an entire array to be set by setting each element
                    459:  * in order, as long as this function is called with the name of
                    460:  * the element before each set operation.
                    461:  */
                    462: int
                    463: structs_array_prep(const struct structs_type *type,
                    464:        const char *name, void *data)
                    465: {
                    466:        char *nbuf;
                    467:        char *s;
                    468: 
                    469:        /* Skip if name cannot be an array element name */
                    470:        if (name == NULL || *name == '\0')
                    471:                return (0);
                    472: 
                    473:        /* Copy name into writable buffer */
                    474:        if ((nbuf = MALLOC(TYPED_MEM_TEMP, strlen(name) + 2)) == NULL)
                    475:                return (-1);
                    476:        nbuf[0] = '*';                                  /* for debugging */
                    477:        strcpy(nbuf + 1, name);
                    478: 
                    479:        /* Check all array element names in name path */
                    480:        for (s = nbuf; s != NULL; s = strchr(s + 1, STRUCTS_SEPARATOR)) {
                    481:                const struct structs_type *atype;
                    482:                struct structs_array *ary = data;
                    483:                u_long index;
                    484:                char *eptr;
                    485:                char *t;
                    486:                char ch;
                    487: 
                    488:                /* Go to next descendant node using prefix of name */
                    489:                ch = *s;
                    490:                *s = '\0';
                    491:                if ((atype = structs_find(type,
                    492:                    nbuf + (s != nbuf), (void **)&ary, 1)) == NULL) {
                    493:                        FREE(TYPED_MEM_TEMP, nbuf);
                    494:                        return (-1);
                    495:                }
                    496:                *s = ch;
                    497: 
                    498:                /* If not array type, continue */
                    499:                if (atype->tclass != STRUCTS_TYPE_ARRAY)
                    500:                        continue;
                    501: 
                    502:                /* Get array index */
                    503:                if ((t = strchr(s + 1, STRUCTS_SEPARATOR)) != NULL)
                    504:                        *t = '\0';
                    505:                index = strtoul(s + 1, &eptr, 10);
                    506:                if (eptr == s + 1 || *eptr != '\0') {
                    507:                        errno = ENOENT;
                    508:                        FREE(TYPED_MEM_TEMP, nbuf);
                    509:                        return (-1);
                    510:                }
                    511: 
                    512:                /* If setting an element that already exists, accept */
                    513:                if (index < ary->length)
                    514:                        goto next;
                    515: 
                    516:                /* Must be setting the next new item in the array */
                    517:                if (index != ary->length) {
                    518:                        errno = ENOENT;
                    519:                        FREE(TYPED_MEM_TEMP, nbuf);
                    520:                        return (-1);
                    521:                }
                    522: 
                    523:                /* Add new item; it will be in an initialized state */
                    524:                if (structs_array_insert(atype, NULL, ary->length, ary) == -1) {
                    525:                        FREE(TYPED_MEM_TEMP, nbuf);
                    526:                        return (-1);
                    527:                }
                    528: 
                    529: next:
                    530:                /* Repair name buffer for next time */
                    531:                if (t != NULL)
                    532:                        *t = STRUCTS_SEPARATOR;
                    533:        }
                    534: 
                    535:        /* Done */
                    536:        FREE(TYPED_MEM_TEMP, nbuf);
                    537:        return (0);
                    538: }
                    539: 
                    540: /*********************************************************************
                    541:                        FIXEDARRAY TYPES
                    542: *********************************************************************/
                    543: 
                    544: int
                    545: structs_fixedarray_init(const struct structs_type *type, void *data)
                    546: {
                    547:        const struct structs_type *const etype = type->args[0].v;
                    548:        const u_int length = type->args[2].i;
                    549:        u_int i;
                    550: 
                    551:        for (i = 0; i < length; i++) {
                    552:                if ((*etype->init)(etype,
                    553:                    (char *)data + (i * etype->size)) == -1) {
                    554:                            while (i-- > 0) {
                    555:                                    (*etype->uninit)(etype,
                    556:                                        (char *)data + (i * etype->size));
                    557:                            }
                    558:                            return (-1);
                    559:                }
                    560:        }
                    561:        return (0);
                    562: }
                    563: 
                    564: int
                    565: structs_fixedarray_copy(const struct structs_type *type,
                    566:        const void *from, void *to)
                    567: {
                    568:        const struct structs_type *const etype = type->args[0].v;
                    569:        const u_int length = type->args[2].i;
                    570:        u_int i;
                    571: 
                    572:        /* Make sure it's really a fixedarray type */
                    573:        if (type->tclass != STRUCTS_TYPE_FIXEDARRAY) {
                    574:                errno = EINVAL;
                    575:                return (-1);
                    576:        }
                    577: 
                    578:        /* Copy elements into it */
                    579:        for (i = 0; i < length; i++) {
                    580:                const void *const from_elem = (char *)from + (i * etype->size);
                    581:                void *const to_elem = (char *)to + (i * etype->size);
                    582: 
                    583:                if ((*etype->copy)(etype, from_elem, to_elem) == -1)
                    584:                        break;
                    585:        }
                    586: 
                    587:        /* If there was a failure, undo the half completed job */
                    588:        if (i < length) {
                    589:                while (i-- > 0)
                    590:                        (*etype->uninit)(etype, (char *)to + (i * etype->size));
                    591:                return (-1);
                    592:        }
                    593: 
                    594:        /* Done */
                    595:        return (0);
                    596: }
                    597: 
                    598: int
                    599: structs_fixedarray_equal(const struct structs_type *type,
                    600:        const void *v1, const void *v2)
                    601: {
                    602:        const struct structs_type *const etype = type->args[0].v;
                    603:        const u_int length = type->args[2].i;
                    604:        u_int i;
                    605: 
                    606:        /* Make sure it's really a fixedarray type */
                    607:        if (type->tclass != STRUCTS_TYPE_FIXEDARRAY)
                    608:                return (0);
                    609: 
                    610:        /* Compare individual elements */
                    611:        for (i = 0;
                    612:            i < length && (*etype->equal)(etype,
                    613:                (char *)v1 + (i * etype->size), (char *)v2 + (i * etype->size));
                    614:            i++);
                    615:        return (i == length);
                    616: }
                    617: 
                    618: int
                    619: structs_fixedarray_encode(const struct structs_type *type, const char *mtype,
                    620:        struct structs_data *code, const void *data)
                    621: {
                    622:        const struct structs_type *const etype = type->args[0].v;
                    623:        const u_int length = type->args[2].i;
                    624:        const u_int bitslen = NUM_BYTES(length);
                    625:        struct structs_data *ecodes;
                    626:        u_char *bits;
                    627:        void *delem;
                    628:        u_int tlen;
                    629:        int r = -1;
                    630:        u_int i;
                    631: 
                    632:        /* Make sure it's really a fixedarray type */
                    633:        if (type->tclass != STRUCTS_TYPE_FIXEDARRAY) {
                    634:                errno = EINVAL;
                    635:                return (-1);
                    636:        }
                    637: 
                    638:        /* Get the default value for an element */
                    639:        if ((delem = MALLOC(TYPED_MEM_TEMP, etype->size)) == NULL)
                    640:                return (-1);
                    641:        if (structs_init(etype, NULL, delem) == -1)
                    642:                goto fail1;
                    643: 
                    644:        /* Create bit array. Each bit indicates an element that is present. */
                    645:        if ((bits = MALLOC(TYPED_MEM_TEMP, bitslen)) == NULL)
                    646:                goto fail2;
                    647:        memset(bits, 0, bitslen);
                    648:        tlen = bitslen;
                    649: 
                    650:        /* Create array of individual encodings, one per element */
                    651:        if ((ecodes = MALLOC(TYPED_MEM_TEMP, length * sizeof(*ecodes))) == NULL)
                    652:                goto fail3;
                    653:        for (i = 0; i < length; i++) {
                    654:                const void *const elem = (char *)data + (i * etype->size);
                    655:                struct structs_data *const ecode = &ecodes[i];
                    656: 
                    657:                /* Check for default value, leave out if same as */
                    658:                if ((*etype->equal)(etype, elem, delem) == 1) {
                    659:                        memset(ecode, 0, sizeof(*ecode));
                    660:                        continue;
                    661:                }
                    662:                bits[i / 8] |= (1 << (i % 8));
                    663: 
                    664:                /* Encode element */
                    665:                if ((*etype->encode)(etype, TYPED_MEM_TEMP, ecode, elem) == -1)
                    666:                        goto fail4;
                    667:                tlen += ecode->length;
                    668:        }
                    669: 
                    670:        /* Allocate final encoded region */
                    671:        if ((code->data = MALLOC(mtype, tlen)) == NULL)
                    672:                goto fail4;
                    673: 
                    674:        /* Copy bits array */
                    675:        memcpy(code->data, bits, bitslen);
                    676:        code->length = bitslen;
                    677: 
                    678:        /* Copy encoded elements */
                    679:        for (i = 0; i < length; i++) {
                    680:                struct structs_data *const ecode = &ecodes[i];
                    681: 
                    682:                memcpy(code->data + code->length, ecode->data, ecode->length);
                    683:                code->length += ecode->length;
                    684:        }
                    685: 
                    686:        /* OK */
                    687:        r = 0;
                    688: 
                    689:        /* Clean up and exit */
                    690: fail4: while (i-- > 0)
                    691:                FREE(TYPED_MEM_TEMP, ecodes[i].data);
                    692:        FREE(TYPED_MEM_TEMP, ecodes);
                    693: fail3: FREE(TYPED_MEM_TEMP, bits);
                    694: fail2: structs_free(etype, NULL, delem);
                    695: fail1: FREE(TYPED_MEM_TEMP, delem);
                    696:        return (r);
                    697: }
                    698: 
                    699: int
                    700: structs_fixedarray_decode(const struct structs_type *type, const u_char *code,
                    701:        size_t cmax, void *data, char *ebuf, size_t emax)
                    702: {
                    703:        const struct structs_type *const etype = type->args[0].v;
                    704:        const u_int length = type->args[2].i;
                    705:        const u_int bitslen = NUM_BYTES(length);
                    706:        const u_char *bits;
                    707:        int clen = 0;
                    708:        u_int i;
                    709: 
                    710:        /* Make sure it's really a fixedarray type */
                    711:        if (type->tclass != STRUCTS_TYPE_FIXEDARRAY) {
                    712:                errno = EINVAL;
                    713:                return (-1);
                    714:        }
                    715: 
                    716:        /* Get bits array */
                    717:        if (cmax < bitslen) {
                    718:                strlcpy(ebuf, "encoded array is truncated", emax);
                    719:                errno = EINVAL;
                    720:                return (-1);
                    721:        }
                    722:        bits = code;
                    723:        code += bitslen;
                    724:        cmax -= bitslen;
                    725:        clen += bitslen;
                    726: 
                    727:        /* Decode elements */
                    728:        for (i = 0; i < length; i++) {
                    729:                void *const edata = (char *)data + (i * etype->size);
                    730:                int eclen;
                    731: 
                    732:                /* If element not present, assign it the default value */
                    733:                if ((bits[i / 8] & (1 << (i % 8))) == 0) {
                    734:                        if (structs_init(etype, NULL, edata) == -1)
                    735:                                goto fail;
                    736:                        continue;
                    737:                }
                    738: 
                    739:                /* Decode element */
                    740:                if ((eclen = (*etype->decode)(etype,
                    741:                    code, cmax, edata, ebuf, emax)) == -1)
                    742:                        goto fail;
                    743: 
                    744:                /* Go to next encoded element */
                    745:                code += eclen;
                    746:                cmax -= eclen;
                    747:                clen += eclen;
                    748:                continue;
                    749: 
                    750:                /* Un-do work done so far */
                    751: fail:          while (i-- > 0) {
                    752:                        structs_free(etype, NULL,
                    753:                            (char *)data + (i * etype->size));
                    754:                }
                    755:                return (-1);
                    756:        }
                    757: 
                    758:        /* Done */
                    759:        return (clen);
                    760: }
                    761: 
                    762: void
                    763: structs_fixedarray_free(const struct structs_type *type, void *data)
                    764: {
                    765:        const struct structs_type *const etype = type->args[0].v;
                    766:        const u_int length = type->args[2].i;
                    767:        u_int i;
                    768: 
                    769:        /* Make sure it's really a fixedarray type */
                    770:        if (type->tclass != STRUCTS_TYPE_FIXEDARRAY)
                    771:                return;
                    772: 
                    773:        /* Free elements */
                    774:        for (i = 0; i < length; i++)
                    775:                (*etype->uninit)(etype, (char *)data + (i * etype->size));
                    776: }
                    777: 

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