/* See LICENSE file for copyright and license details. */ #include "liblss16.h" #include #include #if defined(__clang__) # pragma clang diagnostic ignored "-Wimplicit-fallthrough" # pragma clang diagnostic ignored "-Wunsafe-buffer-usage" #endif static size_t flush_buffer(struct liblss16_encoder *encoder, uint8_t *buffer, size_t size) { size_t i; for (i = 0; size && encoder->nbuffered - i > 1U; i += 2U, size--) buffer[i] = (uint8_t)(encoder->buffered[i + 0] | (encoder->buffered[i + 1] << 4)); memmove(&encoder->buffered[0], &encoder->buffered[i], encoder->nbuffered - i); return i; } enum liblss16_encode_state liblss16_encode_from_colour_index(struct liblss16_encoder *encoder, void *buffer_, size_t size, size_t *written_out, const uint8_t *pixels, size_t npixels, size_t *nconsumed_out) { uint8_t *buffer = buffer_; size_t n; *written_out = 0; *nconsumed_out = 0; switch (encoder->header_position) { case 0: if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = (uint8_t)0x3DU; ++*nconsumed_out; encoder->header_position++; /* fall through */ case 1: if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = (uint8_t)0xF3U; ++*nconsumed_out; encoder->header_position++; /* fall through */ case 2: if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = (uint8_t)0x13U; ++*nconsumed_out; encoder->header_position++; /* fall through */ case 3: if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = (uint8_t)0x14U; ++*nconsumed_out; encoder->header_position++; /* fall through */ case 4: if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = (uint8_t)encoder->header.width; ++*nconsumed_out; encoder->header_position++; /* fall through */ case 5: if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = (uint8_t)(encoder->header.width >> 8); ++*nconsumed_out; encoder->header_position++; /* fall through */ case 6: if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = (uint8_t)encoder->header.height; ++*nconsumed_out; encoder->header_position++; /* fall through */ case 7: if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = (uint8_t)(encoder->header.height >> 8); ++*nconsumed_out; encoder->header_position++; /* fall through */ default: break; } while (encoder->header_position < 8U + 16U * 3U) { if (!size--) return LIBLSS16_ENCODE_RUNNING; *buffer++ = ((const uint8_t *)encoder->header.colour_map)[encoder->header_position++]; ++*nconsumed_out; encoder->header_position++; } if (encoder->nbuffered > 1U) { n = flush_buffer(encoder, buffer, size); buffer = &buffer[n]; size -= n; *written_out += n; if (encoder->nbuffered > 1U) return LIBLSS16_ENCODE_RUNNING; if (!encoder->y_rem) { if (encoder->nbuffered) abort(); return LIBLSS16_ENCODE_DONE; } } while (npixels--) { if (*pixels == encoder->previous) { encoder->repetition++; } else { if (!encoder->repetition) { /* do nothing */ } else if (encoder->repetition < 16U) { encoder->buffered[encoder->nbuffered++] = encoder->previous; encoder->buffered[encoder->nbuffered++] = (uint8_t)encoder->repetition; } else { unsigned value = encoder->repetition - 16U; encoder->buffered[encoder->nbuffered++] = encoder->previous; encoder->buffered[encoder->nbuffered++] = 0; encoder->buffered[encoder->nbuffered++] = (uint8_t)(value & 15U); encoder->buffered[encoder->nbuffered++] = (uint8_t)(value >> 4); } encoder->buffered[encoder->nbuffered++] = *pixels; encoder->previous = *pixels; encoder->repetition = 0; n = flush_buffer(encoder, buffer, size); buffer = &buffer[n]; size -= n; *written_out += n; if (encoder->nbuffered > 1U) return LIBLSS16_ENCODE_RUNNING; } ++pixels; ++*nconsumed_out; if (!--encoder->x_rem) { encoder->previous = 0; encoder->repetition = 0; encoder->x_rem = encoder->header.width; encoder->y_rem--; if (encoder->nbuffered & 1) encoder->buffered[encoder->nbuffered++] = 0; n = flush_buffer(encoder, buffer, size); buffer = &buffer[n]; size -= n; *written_out += n; if (encoder->nbuffered > 1U) return LIBLSS16_ENCODE_RUNNING; else if (encoder->nbuffered) abort(); if (!encoder->y_rem) return LIBLSS16_ENCODE_DONE; } } return LIBLSS16_ENCODE_RUNNING; }