/* * This file is part of the Aaru Data Preservation Suite. * Copyright (c) 2019-2025 Natalia Portillo. * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include #include #include #include "aaruformat.h" /** * @brief Transforms interleaved subchannel data to sequential format. * * Converts interleaved subchannel data into a sequential format for further processing. * * @param interleaved Pointer to the interleaved data buffer. * @param sequential Pointer to the output sequential data buffer. * @param length Length of the data buffer. * @return AARUF_STATUS_OK on success, or an error code on failure. */ int32_t aaruf_cst_transform(const uint8_t *interleaved, uint8_t *sequential, size_t length) { uint8_t *p = NULL; uint8_t *q = NULL; uint8_t *r = NULL; uint8_t *s = NULL; uint8_t *t = NULL; uint8_t *u = NULL; uint8_t *v = NULL; uint8_t *w = NULL; size_t q_start = 0; size_t r_start = 0; size_t s_start = 0; size_t t_start = 0; size_t u_start = 0; size_t v_start = 0; size_t w_start = 0; size_t i = 0; if(interleaved == NULL || sequential == NULL) return AARUF_ERROR_BUFFER_TOO_SMALL; p = malloc(length / 8); q = malloc(length / 8); r = malloc(length / 8); s = malloc(length / 8); t = malloc(length / 8); u = malloc(length / 8); v = malloc(length / 8); w = malloc(length / 8); if(p == NULL || q == NULL || r == NULL || s == NULL || t == NULL || u == NULL || v == NULL || w == NULL) { free(p); free(q); free(r); free(s); free(t); free(u); free(v); free(w); return AARUF_ERROR_NOT_ENOUGH_MEMORY; } for(i = 0; i < length; i += 8) { p[i / 8] = (uint8_t)(interleaved[i] & 0x80); p[i / 8] += (interleaved[i + 1] & 0x80) >> 1; p[i / 8] += (interleaved[i + 2] & 0x80) >> 2; p[i / 8] += (interleaved[i + 3] & 0x80) >> 3; p[i / 8] += (interleaved[i + 4] & 0x80) >> 4; p[i / 8] += (interleaved[i + 5] & 0x80) >> 5; p[i / 8] += (interleaved[i + 6] & 0x80) >> 6; p[i / 8] += (interleaved[i + 7] & 0x80) >> 7; q[i / 8] = (uint8_t)((interleaved[i] & 0x40) << 1); q[i / 8] += interleaved[i + 1] & 0x40; q[i / 8] += (interleaved[i + 2] & 0x40) >> 1; q[i / 8] += (interleaved[i + 3] & 0x40) >> 2; q[i / 8] += (interleaved[i + 4] & 0x40) >> 3; q[i / 8] += (interleaved[i + 5] & 0x40) >> 4; q[i / 8] += (interleaved[i + 6] & 0x40) >> 5; q[i / 8] += (interleaved[i + 7] & 0x40) >> 6; r[i / 8] = (uint8_t)((interleaved[i] & 0x20) << 2); r[i / 8] += (interleaved[i + 1] & 0x20) << 1; r[i / 8] += interleaved[i + 2] & 0x20; r[i / 8] += (interleaved[i + 3] & 0x20) >> 1; r[i / 8] += (interleaved[i + 4] & 0x20) >> 2; r[i / 8] += (interleaved[i + 5] & 0x20) >> 3; r[i / 8] += (interleaved[i + 6] & 0x20) >> 4; r[i / 8] += (interleaved[i + 7] & 0x20) >> 5; s[i / 8] = (uint8_t)((interleaved[i] & 0x10) << 3); s[i / 8] += (interleaved[i + 1] & 0x10) << 2; s[i / 8] += (interleaved[i + 2] & 0x10) << 1; s[i / 8] += interleaved[i + 3] & 0x10; s[i / 8] += (interleaved[i + 4] & 0x10) >> 1; s[i / 8] += (interleaved[i + 5] & 0x10) >> 2; s[i / 8] += (interleaved[i + 6] & 0x10) >> 3; s[i / 8] += (interleaved[i + 7] & 0x10) >> 4; t[i / 8] = (uint8_t)((interleaved[i] & 0x08) << 4); t[i / 8] += (interleaved[i + 1] & 0x08) << 3; t[i / 8] += (interleaved[i + 2] & 0x08) << 2; t[i / 8] += (interleaved[i + 3] & 0x08) << 1; t[i / 8] += interleaved[i + 4] & 0x08; t[i / 8] += (interleaved[i + 5] & 0x08) >> 1; t[i / 8] += (interleaved[i + 6] & 0x08) >> 2; t[i / 8] += (interleaved[i + 7] & 0x08) >> 3; u[i / 8] = (uint8_t)((interleaved[i] & 0x04) << 5); u[i / 8] += (interleaved[i + 1] & 0x04) << 4; u[i / 8] += (interleaved[i + 2] & 0x04) << 3; u[i / 8] += (interleaved[i + 3] & 0x04) << 2; u[i / 8] += (interleaved[i + 4] & 0x04) << 1; u[i / 8] += interleaved[i + 5] & 0x04; u[i / 8] += (interleaved[i + 6] & 0x04) >> 1; u[i / 8] += (interleaved[i + 7] & 0x04) >> 2; v[i / 8] = (uint8_t)((interleaved[i] & 0x02) << 6); v[i / 8] += (interleaved[i + 1] & 0x02) << 5; v[i / 8] += (interleaved[i + 2] & 0x02) << 4; v[i / 8] += (interleaved[i + 3] & 0x02) << 3; v[i / 8] += (interleaved[i + 4] & 0x02) << 2; v[i / 8] += (interleaved[i + 5] & 0x02) << 1; v[i / 8] += interleaved[i + 6] & 0x02; v[i / 8] += (interleaved[i + 7] & 0x02) >> 1; w[i / 8] = (uint8_t)((interleaved[i] & 0x01) << 7); w[i / 8] += (interleaved[i + 1] & 0x01) << 6; w[i / 8] += (interleaved[i + 2] & 0x01) << 5; w[i / 8] += (interleaved[i + 3] & 0x01) << 4; w[i / 8] += (interleaved[i + 4] & 0x01) << 3; w[i / 8] += (interleaved[i + 5] & 0x01) << 2; w[i / 8] += (interleaved[i + 6] & 0x01) << 1; w[i / 8] += interleaved[i + 7] & 0x01; } q_start = (length / 8) * 1; r_start = (length / 8) * 2; s_start = (length / 8) * 3; t_start = (length / 8) * 4; u_start = (length / 8) * 5; v_start = (length / 8) * 6; w_start = (length / 8) * 7; for(i = 0; i < (length / 8); i++) { sequential[i] = p[i]; sequential[q_start + i] = q[i]; sequential[r_start + i] = r[i]; sequential[s_start + i] = s[i]; sequential[t_start + i] = t[i]; sequential[u_start + i] = u[i]; sequential[v_start + i] = v[i]; sequential[w_start + i] = w[i]; } free(p); free(q); free(r); free(s); free(t); free(u); free(v); free(w); return AARUF_STATUS_OK; } /** * @brief Reverses the CST (Claunia's Subchannel Transform) transformation from sequential to interleaved data. * * @param sequential Pointer to the sequential data buffer. * @param interleaved Pointer to the output buffer for interleaved data. * @param length Length of the data in bytes. * @return AARUF_STATUS_OK on success, or an error code on failure. */ int32_t aaruf_cst_untransform(const uint8_t *sequential, uint8_t *interleaved, size_t length) { uint8_t *p, *q, *r, *s, *t, *u, *v, *w; size_t q_start; size_t r_start; size_t s_start; size_t t_start; size_t u_start; size_t v_start; size_t w_start; size_t i; if(interleaved == NULL || sequential == NULL) return AARUF_ERROR_BUFFER_TOO_SMALL; p = malloc(length / 8); q = malloc(length / 8); r = malloc(length / 8); s = malloc(length / 8); t = malloc(length / 8); u = malloc(length / 8); v = malloc(length / 8); w = malloc(length / 8); if(p == NULL || q == NULL || r == NULL || s == NULL || t == NULL || u == NULL || v == NULL || w == NULL) { free(p); free(q); free(r); free(s); free(t); free(u); free(v); free(w); return AARUF_ERROR_NOT_ENOUGH_MEMORY; } q_start = (length / 8) * 1; r_start = (length / 8) * 2; s_start = (length / 8) * 3; t_start = (length / 8) * 4; u_start = (length / 8) * 5; v_start = (length / 8) * 6; w_start = (length / 8) * 7; for(i = 0; i < (length / 8); i++) { p[i] = sequential[i]; q[i] = sequential[q_start + i]; r[i] = sequential[r_start + i]; s[i] = sequential[s_start + i]; t[i] = sequential[t_start + i]; u[i] = sequential[u_start + i]; v[i] = sequential[v_start + i]; w[i] = sequential[w_start + i]; } memset(interleaved, 0, length); for(i = 0; i < length; i += 8) { interleaved[i] += ((p[i / 8] & 0x80) == 0x80 ? 0x80 : 0); interleaved[i + 1] += ((p[i / 8] & 0x40) == 0x40 ? 0x80 : 0); interleaved[i + 2] += ((p[i / 8] & 0x20) == 0x20 ? 0x80 : 0); interleaved[i + 3] += ((p[i / 8] & 0x10) == 0x10 ? 0x80 : 0); interleaved[i + 4] += ((p[i / 8] & 0x08) == 0x08 ? 0x80 : 0); interleaved[i + 5] += ((p[i / 8] & 0x04) == 0x04 ? 0x80 : 0); interleaved[i + 6] += ((p[i / 8] & 0x02) == 0x02 ? 0x80 : 0); interleaved[i + 7] += ((p[i / 8] & 0x01) == 0x01 ? 0x80 : 0); interleaved[i] += ((q[i / 8] & 0x80) == 0x80 ? 0x40 : 0); interleaved[i + 1] += ((q[i / 8] & 0x40) == 0x40 ? 0x40 : 0); interleaved[i + 2] += ((q[i / 8] & 0x20) == 0x20 ? 0x40 : 0); interleaved[i + 3] += ((q[i / 8] & 0x10) == 0x10 ? 0x40 : 0); interleaved[i + 4] += ((q[i / 8] & 0x08) == 0x08 ? 0x40 : 0); interleaved[i + 5] += ((q[i / 8] & 0x04) == 0x04 ? 0x40 : 0); interleaved[i + 6] += ((q[i / 8] & 0x02) == 0x02 ? 0x40 : 0); interleaved[i + 7] += ((q[i / 8] & 0x01) == 0x01 ? 0x40 : 0); interleaved[i] += ((r[i / 8] & 0x80) == 0x80 ? 0x20 : 0); interleaved[i + 1] += ((r[i / 8] & 0x40) == 0x40 ? 0x20 : 0); interleaved[i + 2] += ((r[i / 8] & 0x20) == 0x20 ? 0x20 : 0); interleaved[i + 3] += ((r[i / 8] & 0x10) == 0x10 ? 0x20 : 0); interleaved[i + 4] += ((r[i / 8] & 0x08) == 0x08 ? 0x20 : 0); interleaved[i + 5] += ((r[i / 8] & 0x04) == 0x04 ? 0x20 : 0); interleaved[i + 6] += ((r[i / 8] & 0x02) == 0x02 ? 0x20 : 0); interleaved[i + 7] += ((r[i / 8] & 0x01) == 0x01 ? 0x20 : 0); interleaved[i] += ((s[i / 8] & 0x80) == 0x80 ? 0x10 : 0); interleaved[i + 1] += ((s[i / 8] & 0x40) == 0x40 ? 0x10 : 0); interleaved[i + 2] += ((s[i / 8] & 0x20) == 0x20 ? 0x10 : 0); interleaved[i + 3] += ((s[i / 8] & 0x10) == 0x10 ? 0x10 : 0); interleaved[i + 4] += ((s[i / 8] & 0x08) == 0x08 ? 0x10 : 0); interleaved[i + 5] += ((s[i / 8] & 0x04) == 0x04 ? 0x10 : 0); interleaved[i + 6] += ((s[i / 8] & 0x02) == 0x02 ? 0x10 : 0); interleaved[i + 7] += ((s[i / 8] & 0x01) == 0x01 ? 0x10 : 0); interleaved[i] += ((t[i / 8] & 0x80) == 0x80 ? 0x08 : 0); interleaved[i + 1] += ((t[i / 8] & 0x40) == 0x40 ? 0x08 : 0); interleaved[i + 2] += ((t[i / 8] & 0x20) == 0x20 ? 0x08 : 0); interleaved[i + 3] += ((t[i / 8] & 0x10) == 0x10 ? 0x08 : 0); interleaved[i + 4] += ((t[i / 8] & 0x08) == 0x08 ? 0x08 : 0); interleaved[i + 5] += ((t[i / 8] & 0x04) == 0x04 ? 0x08 : 0); interleaved[i + 6] += ((t[i / 8] & 0x02) == 0x02 ? 0x08 : 0); interleaved[i + 7] += ((t[i / 8] & 0x01) == 0x01 ? 0x08 : 0); interleaved[i] += ((u[i / 8] & 0x80) == 0x80 ? 0x04 : 0); interleaved[i + 1] += ((u[i / 8] & 0x40) == 0x40 ? 0x04 : 0); interleaved[i + 2] += ((u[i / 8] & 0x20) == 0x20 ? 0x04 : 0); interleaved[i + 3] += ((u[i / 8] & 0x10) == 0x10 ? 0x04 : 0); interleaved[i + 4] += ((u[i / 8] & 0x08) == 0x08 ? 0x04 : 0); interleaved[i + 5] += ((u[i / 8] & 0x04) == 0x04 ? 0x04 : 0); interleaved[i + 6] += ((u[i / 8] & 0x02) == 0x02 ? 0x04 : 0); interleaved[i + 7] += ((u[i / 8] & 0x01) == 0x01 ? 0x04 : 0); interleaved[i] += ((v[i / 8] & 0x80) == 0x80 ? 0x02 : 0); interleaved[i + 1] += ((v[i / 8] & 0x40) == 0x40 ? 0x02 : 0); interleaved[i + 2] += ((v[i / 8] & 0x20) == 0x20 ? 0x02 : 0); interleaved[i + 3] += ((v[i / 8] & 0x10) == 0x10 ? 0x02 : 0); interleaved[i + 4] += ((v[i / 8] & 0x08) == 0x08 ? 0x02 : 0); interleaved[i + 5] += ((v[i / 8] & 0x04) == 0x04 ? 0x02 : 0); interleaved[i + 6] += ((v[i / 8] & 0x02) == 0x02 ? 0x02 : 0); interleaved[i + 7] += ((v[i / 8] & 0x01) == 0x01 ? 0x02 : 0); interleaved[i] += ((w[i / 8] & 0x80) == 0x80 ? 0x01 : 0); interleaved[i + 1] += ((w[i / 8] & 0x40) == 0x40 ? 0x01 : 0); interleaved[i + 2] += ((w[i / 8] & 0x20) == 0x20 ? 0x01 : 0); interleaved[i + 3] += ((w[i / 8] & 0x10) == 0x10 ? 0x01 : 0); interleaved[i + 4] += ((w[i / 8] & 0x08) == 0x08 ? 0x01 : 0); interleaved[i + 5] += ((w[i / 8] & 0x04) == 0x04 ? 0x01 : 0); interleaved[i + 6] += ((w[i / 8] & 0x02) == 0x02 ? 0x01 : 0); interleaved[i + 7] += ((w[i / 8] & 0x01) == 0x01 ? 0x01 : 0); } free(p); free(q); free(r); free(s); free(t); free(u); free(v); free(w); return AARUF_STATUS_OK; }