Annotation of embedaddon/mpd/src/contrib/libpdel/structs/type/structs_type_array.c, revision 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>