decode.c 17 KB
Newer Older
1 2 3 4 5 6 7 8 9
/* Adaptive Entropy Decoder            */
/* CCSDS 121.0-B-1 and CCSDS 120.0-G-2 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
10
#include "libaec.h"
11

12 13
#define MIN(a, b) (((a) < (b))? (a): (b))

14
#define SAFE (strm->avail_in >= state->in_blklen        \
15
              && strm->avail_out >= state->out_blklen)
16 17 18 19

#define ROS 5

typedef struct internal_state {
20
    int id;            /* option ID */
21
    int id_len;        /* bit length of code option identification key */
22
    int *id_table;     /* table maps IDs to states */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
23
    void (*put_sample)(struct aec_stream *, int64_t);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
24
    int ref_int;       /* reference sample is every ref_int samples */
25
    int64_t last_out;  /* previous output for post-processing */
26 27 28
    int64_t xmin;      /* minimum integer for post-processing */
    int64_t xmax;      /* maximum integer for post-processing */
    int mode;          /* current mode of FSM */
29
    int in_blklen;     /* length of uncompressed input block
30
                          should be the longest possible block */
31
    int out_blklen;    /* length of output block in bytes */
32 33
    int n, i;          /* counter for samples */
    int64_t *block;    /* block buffer for split-sample options */
34 35
    int se;            /* set if second extension option is selected */
    uint64_t acc;      /* accumulator for currently used bit sequence */
36 37
    int bitp;          /* bit pointer to the next unused bit in accumulator */
    int fs;            /* last fundamental sequence in accumulator */
38
    int ref;           /* 1 if current block has reference sample */
39
    int pp;            /* 1 if postprocessor has to be used */
40
    int byte_per_sample;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
41
    size_t samples_out;
42 43 44
} decode_state;

/* decoding table for the second-extension option */
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
45
static const int second_extension[92][2] = {
46 47 48 49 50 51 52
    {0, 0},
    {1, 1}, {1, 1},
    {2, 3}, {2, 3}, {2, 3},
    {3, 6}, {3, 6}, {3, 6}, {3, 6},
    {4, 10}, {4, 10}, {4, 10}, {4, 10}, {4, 10},
    {5, 15}, {5, 15}, {5, 15}, {5, 15}, {5, 15}, {5, 15},
    {6, 21}, {6, 21}, {6, 21}, {6, 21}, {6, 21}, {6, 21}, {6, 21},
53 54 55 56 57 58
    {7, 28}, {7, 28}, {7, 28}, {7, 28}, {7, 28}, {7, 28}, {7, 28}, {7, 28},
    {8, 36}, {8, 36}, {8, 36}, {8, 36}, {8, 36}, {8, 36}, {8, 36}, {8, 36}, {8, 36},
    {9, 45}, {9, 45}, {9, 45}, {9, 45}, {9, 45}, {9, 45}, {9, 45}, {9, 45}, {9, 45}, {9, 45},
    {10, 55}, {10, 55}, {10, 55}, {10, 55}, {10, 55}, {10, 55}, {10, 55}, {10, 55}, {10, 55}, {10, 55}, {10, 55},
    {11, 66}, {11, 66}, {11, 66}, {11, 66}, {11, 66}, {11, 66}, {11, 66}, {11, 66}, {11, 66}, {11, 66}, {11, 66}, {11, 66},
    {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}, {12, 78}
59 60
};

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
61
enum {
62 63 64 65 66 67 68 69 70 71 72 73
    M_ID = 0,
    M_SPLIT,
    M_SPLIT_FS,
    M_SPLIT_OUTPUT,
    M_LOW_ENTROPY,
    M_LOW_ENTROPY_REF,
    M_ZERO_BLOCK,
    M_ZERO_OUTPUT,
    M_SE,
    M_SE_DECODE,
    M_UNCOMP,
    M_UNCOMP_COPY,
74 75
};

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
76
static void put_msb_32(struct aec_stream *strm, int64_t data)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
77 78 79 80 81 82 83 84 85
{
    *strm->next_out++ = data >> 24;
    *strm->next_out++ = data >> 16;
    *strm->next_out++ = data >> 8;
    *strm->next_out++ = data;
    strm->avail_out -= 4;
    strm->total_out += 4;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
86
static void put_msb_24(struct aec_stream *strm, int64_t data)
87 88 89 90 91 92 93 94
{
    *strm->next_out++ = data >> 16;
    *strm->next_out++ = data >> 8;
    *strm->next_out++ = data;
    strm->avail_out -= 3;
    strm->total_out += 3;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
95
static void put_msb_16(struct aec_stream *strm, int64_t data)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
96 97 98 99 100 101 102
{
    *strm->next_out++ = data >> 8;
    *strm->next_out++ = data;
    strm->avail_out -= 2;
    strm->total_out += 2;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
103
static void put_lsb_32(struct aec_stream *strm, int64_t data)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
104 105 106 107 108 109 110 111 112
{
    *strm->next_out++ = data;
    *strm->next_out++ = data >> 8;
    *strm->next_out++ = data >> 16;
    *strm->next_out++ = data >> 24;
    strm->avail_out -= 4;
    strm->total_out += 4;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
113
static void put_lsb_24(struct aec_stream *strm, int64_t data)
114 115 116 117 118 119 120 121
{
    *strm->next_out++ = data;
    *strm->next_out++ = data >> 8;
    *strm->next_out++ = data >> 16;
    strm->avail_out -= 3;
    strm->total_out += 3;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
122
static void put_lsb_16(struct aec_stream *strm, int64_t data)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
123 124 125 126 127 128
{
    *strm->next_out++ = data;
    *strm->next_out++ = data >> 8;
    strm->avail_out -= 2;
    strm->total_out += 2;
}
129

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
130
static void put_8(struct aec_stream *strm, int64_t data)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
131 132 133 134 135
{
    *strm->next_out++ = data;
    strm->avail_out--;
    strm->total_out++;
}
136

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
137
static inline void u_put(struct aec_stream *strm, int64_t sample)
138
{
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
139 140
    int64_t x, d, th, D, lower;
    decode_state *state = strm->state;
141

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
142
    if (state->pp && (state->samples_out % state->ref_int != 0)) {
143 144
        d = sample;
        x = state->last_out;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
145 146
        lower = x - state->xmin;
        th = MIN(lower, state->xmax - x);
147

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
148
        if (d <= 2 * th) {
149 150 151 152 153
            if (d & 1)
                D = - (d + 1) / 2;
            else
                D = d / 2;
        } else {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
154
            if (th == lower)
155 156 157 158 159
                D = d - th;
            else
                D = th - d;
        }
        sample = x + D;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
160 161
    } else {
        if (strm->flags & AEC_DATA_SIGNED) {
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
162 163 164 165 166
            int m = 64 - strm->bit_per_sample;
            /* Reference samples have to be sign extended */
            sample = (sample << m) >> m;
        }
    }
167 168
    state->last_out = sample;
    state->put_sample(strm, sample);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
169
    state->samples_out++;
170 171
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
172
static inline int64_t u_get(struct aec_stream *strm, unsigned int n)
173 174 175 176 177 178 179 180 181 182
{
    /**
       Unsafe get n bit from input stream

       No checking whatsoever. Read bits are dumped.
     */

    decode_state *state;

    state = strm->state;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
183
    while (state->bitp < n) {
184 185
        strm->avail_in--;
        strm->total_in++;
186
        state->acc = (state->acc << 8) | *strm->next_in++;
187 188 189 190 191 192
        state->bitp += 8;
    }
    state->bitp -= n;
    return (state->acc >> state->bitp) & ((1ULL << n) - 1);
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
193
static inline int64_t u_get_fs(struct aec_stream *strm)
194 195 196 197 198 199 200 201
{
    /**
       Interpret a Fundamental Sequence from the input buffer.

       Essentially counts the number of 0 bits until a
       1 is encountered. TODO: faster version.
     */

202
    int64_t fs = 0;
203 204 205 206 207 208 209

    while(u_get(strm, 1) == 0)
        fs++;

    return fs;
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
210
static inline void fast_split(struct aec_stream *strm)
211
{
212
    int i, k;
213 214 215 216 217
    decode_state *state;

    state = strm->state;
    k = state->id - 1;

218
    if (state->ref)
219
        u_put(strm, u_get(strm, strm->bit_per_sample));
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
220

221
    for (i = state->ref; i < strm->block_size; i++)
222 223
        state->block[i] = u_get_fs(strm) << k;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
224
    for (i = state->ref; i < strm->block_size; i++) {
225 226 227 228 229
        state->block[i] += u_get(strm, k);
        u_put(strm, state->block[i]);
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
230
static inline void fast_zero(struct aec_stream *strm)
231 232 233 234 235 236 237
{
    int i = strm->state->i;

    while (i--)
        u_put(strm, 0);
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
238
static inline void fast_se(struct aec_stream *strm)
239 240
{
    int i;
241
    int64_t gamma, beta, ms, delta1;
242

243
    i = strm->state->ref;
244

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
245
    while (i < strm->block_size) {
246 247 248 249
        gamma = u_get_fs(strm);
        beta = second_extension[gamma][0];
        ms = second_extension[gamma][1];
        delta1 = gamma - ms;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
250

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
251
        if ((i & 1) == 0) {
252 253 254 255 256 257 258 259
            u_put(strm, beta - delta1);
            i++;
        }
        u_put(strm, delta1);
        i++;
    }
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
260
static inline void fast_uncomp(struct aec_stream *strm)
261 262 263 264 265
{
    int i;

    for (i = 0; i < strm->block_size; i++)
        u_put(strm, u_get(strm, strm->bit_per_sample));
266 267
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
268
int aec_decode_init(struct aec_stream *strm)
269
{
270 271 272 273
    int i, modi;
    decode_state *state;

    if (strm->bit_per_sample > 32 || strm->bit_per_sample == 0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
274
        return AEC_CONF_ERROR;
275 276 277

    state = (decode_state *) malloc(sizeof(decode_state));
    if (state == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
278
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
279

280 281
    strm->state = state;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
282
    if (strm->bit_per_sample > 16) {
283
        state->id_len = 5;
284

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
285
        if (strm->bit_per_sample <= 24 && strm->flags & AEC_DATA_3BYTE) {
286
            state->byte_per_sample = 3;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
287
            if (strm->flags & AEC_DATA_MSB)
288 289 290
                state->put_sample = put_msb_24;
            else
                state->put_sample = put_lsb_24;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
291
        } else {
292
            state->byte_per_sample = 4;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
293
            if (strm->flags & AEC_DATA_MSB)
294 295 296 297 298 299
                state->put_sample = put_msb_32;
            else
                state->put_sample = put_lsb_32;
        }
        state->out_blklen = strm->block_size
            * state->byte_per_sample;
300
    }
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
301
    else if (strm->bit_per_sample > 8) {
302
        state->byte_per_sample = 2;
303
        state->id_len = 4;
304
        state->out_blklen = strm->block_size * 2;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
305
        if (strm->flags & AEC_DATA_MSB)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
306
            state->put_sample = put_msb_16;
307
        else
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
308
            state->put_sample = put_lsb_16;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
309
    } else {
310
        state->byte_per_sample = 1;
311
        state->id_len = 3;
312
        state->out_blklen = strm->block_size;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
313
        state->put_sample = put_8;
314 315
    }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
316
    if (strm->flags & AEC_DATA_SIGNED) {
317 318
        state->xmin = -(1ULL << (strm->bit_per_sample - 1));
        state->xmax = (1ULL << (strm->bit_per_sample - 1)) - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
319
    } else {
320 321 322
        state->xmin = 0;
        state->xmax = (1ULL << strm->bit_per_sample) - 1;
    }
323

324
    state->ref_int = strm->block_size * strm->rsi;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
325
    state->in_blklen = (strm->block_size * strm->bit_per_sample
326 327 328 329 330
                        + state->id_len) / 8 + 1;

    modi = 1UL << state->id_len;
    state->id_table = (int *)malloc(modi * sizeof(int));
    if (state->id_table == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
331
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
332

333
    state->id_table[0] = M_LOW_ENTROPY;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
334
    for (i = 1; i < modi - 1; i++) {
335 336 337 338
        state->id_table[i] = M_SPLIT;
    }
    state->id_table[modi - 1] = M_UNCOMP;

339
    state->block = (int64_t *)malloc(strm->block_size * sizeof(int64_t));
340
    if (state->block == NULL)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
341
        return AEC_MEM_ERROR;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
342

343 344 345
    strm->total_in = 0;
    strm->total_out = 0;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
346
    state->samples_out = 0;
347
    state->bitp = 0;
348
    state->fs = 0;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
349
    state->pp = strm->flags & AEC_DATA_PREPROCESS;
350
    state->mode = M_ID;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
351
    return AEC_OK;
352 353
}

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
354
int aec_decode_end(struct aec_stream *strm)
355 356 357 358 359 360 361
{
    decode_state *state;

    state = strm->state;
    free(state->block);
    free(state->id_table);
    free(state);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
362
    return AEC_OK;
363 364
}

365 366
#define ASK(n)                                           \
    do {                                                 \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
367 368 369
        while (state->bitp < (unsigned)(n)) {            \
            if (strm->avail_in == 0)                     \
                goto req_buffer;                         \
370 371 372
            strm->avail_in--;                            \
            strm->total_in++;                            \
            state->acc <<= 8;                            \
373
            state->acc |= *strm->next_in++;              \
374 375
            state->bitp += 8;                            \
        }                                                \
376
    } while (0)
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
377

378 379 380 381 382
#define GET(n)                                                  \
    ((state->acc >> (state->bitp - (n))) & ((1ULL << (n)) - 1))

#define DROP(n) state->bitp -= (unsigned)(n)

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
#define ASKFS()                                                     \
    do {                                                            \
        ASK(1);                                                     \
        while ((state->acc & (1ULL << (state->bitp - 1))) == 0) {   \
            if (state->bitp == 1) {                                 \
                if (strm->avail_in == 0)                            \
                    goto req_buffer;                                \
                strm->avail_in--;                                   \
                strm->total_in++;                                   \
                state->acc <<= 8;                                   \
                state->acc |= *strm->next_in++;                     \
                state->bitp += 8;                                   \
            }                                                       \
            state->fs++;                                            \
            state->bitp--;                                          \
        }                                                           \
399
    } while (0)
400 401 402

#define GETFS() state->fs

403 404 405 406 407 408 409
#define DROPFS()                                \
    do {                                        \
        state->fs = 0;                          \
        /* Needs to be here for                 \
           ASK/GET/PUT/DROP interleaving. */    \
        state->bitp--;                          \
    } while (0)
410 411 412

#define PUT(sample)                                \
    do {                                           \
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
413 414
        if (strm->avail_out == 0)                  \
            goto req_buffer;                       \
415 416 417 418 419 420 421 422 423 424 425
        u_put(strm, (sample));                     \
    } while (0)

#define COPYSAMPLE()                    \
    do {                                \
        ASK(strm->bit_per_sample);      \
        PUT(GET(strm->bit_per_sample)); \
        DROP(strm->bit_per_sample);     \
    } while (0)


Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
426
int aec_decode(struct aec_stream *strm, int flush)
427
{
428 429 430 431 432 433 434 435 436
    /**
       Finite-state machine implementation of the adaptive entropy
       decoder.

       Can work with one byte input und one sample output buffers. If
       enough buffer space is available, then faster implementations
       of the states are called. Inspired by zlib.
    */

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
437
    int zero_blocks;
438
    int64_t gamma, beta, ms, delta1;
439 440 441 442 443
    int k;
    decode_state *state;

    state = strm->state;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
444 445
    for (;;) {
        switch(state->mode) {
446
        case M_ID:
447
            if (state->pp
448
                && (state->samples_out / strm->block_size) % strm->rsi == 0)
449 450 451 452 453 454 455
                state->ref = 1;
            else
                state->ref = 0;

            ASK(state->id_len);
            state->id = GET(state->id_len);
            DROP(state->id_len);
456 457 458 459
            state->mode = state->id_table[state->id];
            break;

        case M_SPLIT:
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
460
            if (SAFE) {
461 462 463 464 465
                fast_split(strm);
                state->mode = M_ID;
                break;
            }

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
466
            if (state->ref) {
467 468
                COPYSAMPLE();
                state->n = strm->block_size - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
469
            } else {
470 471 472
                state->n = strm->block_size;
            }

473
            state->i = state->n - 1;
474 475 476
            state->mode = M_SPLIT_FS;

        case M_SPLIT_FS:
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
477
            do {
478
                ASKFS();
479
                state->block[state->i] = GETFS();
480
                DROPFS();
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
481
            } while(state->i--);
482

483
            state->i = state->n - 1;
484
            state->mode = M_SPLIT_OUTPUT;
485

486
        case M_SPLIT_OUTPUT:
487
            k = state->id - 1;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
488
            do {
489
                ASK(k);
490
                PUT((state->block[state->i] << k) + GET(k));
491
                DROP(k);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
492
            } while(state->i--);
493 494 495 496 497 498 499 500 501 502 503

            state->mode = M_ID;
            break;

        case M_LOW_ENTROPY:
            ASK(1);
            state->id = GET(1);
            DROP(1);
            state->mode = M_LOW_ENTROPY_REF;

        case M_LOW_ENTROPY_REF:
504
            if (state->ref)
505 506
                COPYSAMPLE();

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
507
            if(state->id == 1) {
508 509 510 511 512 513 514 515 516 517 518
                state->mode = M_SE;
                break;
            }

            state->mode = M_ZERO_BLOCK;

        case M_ZERO_BLOCK:
            ASKFS();
            zero_blocks = GETFS() + 1;
            DROPFS();

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
519
            if (zero_blocks == ROS) {
520
                zero_blocks =  64 - (
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
521
                    (state->samples_out / strm->block_size)
522
                    % strm->rsi % 64);
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
523
            } else if (zero_blocks > ROS) {
524 525
                zero_blocks--;
            }
526

527
            if (state->ref)
528 529 530 531
                state->i = zero_blocks * strm->block_size - 1;
            else
                state->i = zero_blocks * strm->block_size;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
532
            if (strm->avail_out >= state->i * state->byte_per_sample) {
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
                fast_zero(strm);
                state->mode = M_ID;
                break;
            }

            state->mode = M_ZERO_OUTPUT;

        case M_ZERO_OUTPUT:
            do
                PUT(0);
            while(--state->i);

            state->mode = M_ID;
            break;

        case M_SE:
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
549
            if (SAFE) {
550 551 552 553 554 555
                fast_se(strm);
                state->mode = M_ID;
                break;
            }

            state->mode = M_SE_DECODE;
556
            state->i = state->ref;
557 558

        case M_SE_DECODE:
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
559
            while(state->i < strm->block_size) {
560
                ASKFS();
561 562 563 564 565
                gamma = GETFS();
                beta = second_extension[gamma][0];
                ms = second_extension[gamma][1];
                delta1 = gamma - ms;

Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
566
                if ((state->i & 1) == 0) {
567 568 569 570 571
                    PUT(beta - delta1);
                    state->i++;
                }

                PUT(delta1);
572
                state->i++;
573
                DROPFS();
574 575
            }

576
            state->mode = M_ID;
577
            break;
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
578

579
        case M_UNCOMP:
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
580
            if (SAFE) {
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
                fast_uncomp(strm);
                state->mode = M_ID;
                break;
            }

            state->i = strm->block_size;
            state->mode = M_UNCOMP_COPY;

        case M_UNCOMP_COPY:
            do
                COPYSAMPLE();
            while(--state->i);

            state->mode = M_ID;
            break;

        default:
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
598
            return AEC_STREAM_ERROR;
599 600
        }
    }
601 602

req_buffer:
Mathis Rosenhauer's avatar
Mathis Rosenhauer committed
603
    return AEC_OK;
604
}