1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 14 янв. 2018 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #include <dsp/endian.h> 23 #include <core/stdlib/string.h> 24 #include <core/files/lspc/lspc.h> 25 #include <core/files/lspc/LSPCChunkReader.h> 26 27 namespace lsp 28 { 29 LSPCChunkReader(LSPCResource * fd,uint32_t magic,uint32_t uid)30 LSPCChunkReader::LSPCChunkReader(LSPCResource *fd, uint32_t magic, uint32_t uid): 31 LSPCChunkAccessor(fd, magic) 32 { 33 nUnread = 0; 34 nBufTail = 0; 35 nFileOff = 0; 36 nUID = uid; 37 bLast = false; 38 } 39 ~LSPCChunkReader()40 LSPCChunkReader::~LSPCChunkReader() 41 { 42 } 43 read(void * buf,size_t count)44 ssize_t LSPCChunkReader::read(void *buf, size_t count) 45 { 46 if (pFile == NULL) 47 return -set_error(STATUS_CLOSED); 48 49 lspc_chunk_header_t hdr; 50 51 uint8_t *dst = static_cast<uint8_t *>(buf); 52 ssize_t total = 0; 53 54 while (count > 0) 55 { 56 size_t to_read = nBufTail - nBufPos; 57 58 if (to_read > 0) // There is data in the buffer? 59 { 60 if (to_read > count) 61 to_read = count; 62 63 // Copy memory from buffer 64 memcpy(dst, &pBuffer[nBufPos], to_read); 65 66 // Update pointer 67 dst += to_read; 68 nBufPos += to_read; 69 count -= to_read; 70 total += to_read; 71 } 72 else if (nUnread > 0) 73 { 74 if (nUnread <= count) 75 { 76 // Read data 77 ssize_t n = pFile->read(nFileOff, dst, nUnread); 78 if (n <= 0) 79 return total; 80 81 // Update pointer 82 dst += n; 83 count -= n; 84 total += n; 85 nUnread -= n; 86 nFileOff += n; 87 } 88 else // Fill buffer 89 { 90 to_read = (nUnread < nBufSize) ? nUnread : nBufSize; 91 92 // Read data 93 ssize_t n = pFile->read(nFileOff, pBuffer, to_read); 94 if (n <= 0) 95 return total; 96 97 // Update pointer 98 nBufPos = 0; 99 nBufTail = n; 100 nFileOff += n; 101 nUnread -= n; 102 } 103 } 104 else // Seek for the next valid chunk 105 { 106 // There is no chunk after current 107 if (bLast) 108 { 109 set_error(STATUS_EOF); 110 return total; 111 } 112 113 // Read chunk header 114 ssize_t n = pFile->read(nFileOff, &hdr, sizeof(lspc_chunk_header_t)); 115 if (n < ssize_t(sizeof(lspc_chunk_header_t))) 116 { 117 set_error(STATUS_EOF); 118 return total; 119 } 120 nFileOff += sizeof(lspc_chunk_header_t); 121 122 hdr.magic = BE_TO_CPU(hdr.magic); 123 hdr.flags = BE_TO_CPU(hdr.flags); 124 hdr.size = BE_TO_CPU(hdr.size); 125 hdr.uid = BE_TO_CPU(hdr.uid); 126 127 // Validate chunk header 128 if ((hdr.magic == nMagic) && (hdr.uid == nUID)) // We've found our chunk, remember unread bytes count 129 { 130 bLast = hdr.flags & LSPC_CHUNK_FLAG_LAST; 131 nUnread = hdr.size; 132 } 133 else // Skip this chunk 134 nFileOff += hdr.size; 135 } 136 } 137 138 return total; 139 } 140 read_header(void * hdr,size_t size)141 ssize_t LSPCChunkReader::read_header(void *hdr, size_t size) 142 { 143 if (size < sizeof(lspc_header_t)) 144 return -set_error(STATUS_BAD_ARGUMENTS); 145 146 // Read header data first 147 lspc_header_t shdr; 148 ssize_t count = read(&shdr, sizeof(lspc_header_t)); 149 if (count < 0) 150 return count; 151 else if (count < ssize_t(sizeof(lspc_header_t))) 152 return -set_error(STATUS_EOF); // Unexpected end of file 153 154 // Now read header 155 lspc_chunk_raw_header_t *dhdr = reinterpret_cast<lspc_chunk_raw_header_t *>(hdr); 156 size_t hdr_size = BE_TO_CPU(shdr.size); 157 if (hdr_size < sizeof(lspc_header_t)) // header size should be at least of sizeof(lspc_header_t) 158 return -set_error(STATUS_CORRUPTED_FILE); 159 dhdr->common.size = hdr_size; 160 dhdr->common.version = BE_TO_CPU(shdr.version); 161 hdr_size -= sizeof(lspc_header_t); 162 size -= sizeof(lspc_header_t); 163 164 // Read header contents 165 ssize_t to_read = (size > hdr_size) ? hdr_size : size; 166 count = read(&dhdr->data, to_read); 167 if (count < 0) 168 return count; 169 else if (count < to_read) 170 return -set_error(STATUS_EOF); // Unexpected end of file 171 172 // Analyze size of header 173 if (size < hdr_size) // Requested size less than actual header size? 174 { 175 // We need to skip extra bytes that do not fit into header 176 to_read = hdr_size - size; 177 count = skip(to_read); 178 if (count < 0) 179 return count; 180 else if (count < to_read) 181 return -set_error(STATUS_EOF); // Unexpected end of file 182 183 // Patch the header size to be at most of size bytes 184 dhdr->common.size = size + sizeof(lspc_header_t); 185 } 186 else if (size > hdr_size) 187 bzero(&dhdr->data[count], size - hdr_size); 188 189 return dhdr->common.size; 190 } 191 skip(size_t count)192 ssize_t LSPCChunkReader::skip(size_t count) 193 { 194 if (pFile == NULL) 195 return -set_error(STATUS_CLOSED); 196 197 lspc_chunk_header_t hdr; 198 199 ssize_t total = 0; 200 201 while (count > 0) 202 { 203 size_t to_read = nBufTail - nBufPos; 204 205 if (to_read > 0) // There is data in the buffer? 206 { 207 if (to_read > count) 208 to_read = count; 209 210 // Update pointer 211 nBufPos += to_read; 212 count -= to_read; 213 total += to_read; 214 } 215 else if (nUnread > 0) 216 { 217 if (nUnread <= count) 218 { 219 // Update counters 220 count -= nUnread; 221 total += nUnread; 222 nFileOff += nUnread; 223 nUnread = 0; 224 } 225 else // Fill buffer 226 { 227 nUnread -= count; 228 nFileOff += count; 229 total += count; 230 count = 0; 231 } 232 } 233 else // Seek for the next valid chunk 234 { 235 // There is no chunk after current 236 if (bLast) 237 { 238 set_error(STATUS_EOF); 239 return total; 240 } 241 242 // Read chunk header 243 ssize_t n = pFile->read(nFileOff, &hdr, sizeof(lspc_chunk_header_t)); 244 if (n < ssize_t(sizeof(lspc_chunk_header_t))) 245 { 246 set_error(STATUS_EOF); 247 return 0; 248 } 249 nFileOff += sizeof(lspc_chunk_header_t); 250 251 hdr.magic = BE_TO_CPU(hdr.magic); 252 hdr.flags = BE_TO_CPU(hdr.flags); 253 hdr.size = BE_TO_CPU(hdr.size); 254 hdr.uid = BE_TO_CPU(hdr.uid); 255 256 // Validate chunk header 257 if ((hdr.magic == nMagic) && (hdr.uid == nUID)) // We've found our chunk, remember unread bytes count 258 { 259 bLast = hdr.flags & LSPC_CHUNK_FLAG_LAST; 260 nUnread = hdr.size; 261 } 262 else // Skip this chunk 263 nFileOff += hdr.size; 264 } 265 } 266 267 return total; 268 } 269 270 } /* namespace lsp */ 271