void pngSetHeader(PngStream* stream) { stream->info.imageWidth = png_get_image_width(stream->png_ptr, stream->info_ptr); stream->info.imageHeight = png_get_image_height(stream->png_ptr, stream->info_ptr); stream->info.numComponents = png_get_channels(stream->png_ptr, stream->info_ptr); stream->info.colorSpace = getPngDecColourType(png_get_color_type(stream->png_ptr, stream->info_ptr)); stream->info.bitDepth = png_get_bit_depth(stream->png_ptr, stream->info_ptr); stream->info.interlaceMethod = png_get_interlace_type(stream->png_ptr, stream->info_ptr); stream->info.chunkInformation = pngDecGetChunkInformation(stream); }
s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, POpenInfo open_info, PCbControlStream control_stream = vm::null, POpenParam open_param = vm::null) { // Check if partial image decoding is used if (control_stream || open_param) { throw EXCEPTION("Partial image decoding is not supported."); } // Allocate memory for the stream structure auto stream = vm::ptr<PngStream>::make(handle->malloc(ppu, sizeof(PngStream), handle->malloc_arg).addr()); // Check if the allocation of memory for the stream structure failed if (!stream) { cellPngDec.error("PNG stream creation failed."); return CELL_PNGDEC_ERROR_FATAL; } // Set memory info open_info->initSpaceAllocated = sizeof(PngStream); // Set the stream source to the source give by the game stream->source = *source; // Indicate that a fixed alpha value isn't used, if not specified otherwise stream->fixed_alpha = false; // Use virtual memory address as a handle *png_stream = stream; // Allocate memory for the PNG buffer for decoding auto buffer = vm::ptr<PngBuffer>::make(handle->malloc(ppu, sizeof(PngBuffer), handle->malloc_arg).addr()); // Check for if the buffer structure allocation failed if (!buffer) { throw EXCEPTION("Memory allocation for the PNG buffer structure failed."); } // We might not be reading from a file stream buffer->file = false; // Set the buffer pointer in the stream structure, so we can later deallocate it stream->buffer = buffer; // Open the buffer/file and check the header u8 header[8]; // Need to test it somewhere if (stream->source.fileOffset != 0) { throw EXCEPTION("Non-0 file offset not supported."); } // Depending on the source type, get the first 8 bytes if (source->srcSelect == CELL_PNGDEC_FILE) { // Open a file stream fs::file file_stream(vfs::get(stream->source.fileName.get_ptr())); // Check if opening of the PNG file failed if (!file_stream) { cellPngDec.error("Opening of PNG failed. (%s)", stream->source.fileName.get_ptr()); return CELL_PNGDEC_ERROR_OPEN_FILE; } // Read the header if (file_stream.read(header, 8) != 8) { cellPngDec.error("PNG header is too small."); return CELL_PNGDEC_ERROR_HEADER; } // Get the file descriptor buffer->fd = idm::make<lv2_file_t>(std::move(file_stream), 0, 0); // Indicate that we need to read from a file stream buffer->file = true; } else { // We can simply copy the first 8 bytes memcpy(header, stream->source.streamPtr.get_ptr(), 8); } // Check if the header indicates a valid PNG file if (png_sig_cmp(header, 0, 8)) { cellPngDec.error("PNG signature is invalid."); return CELL_PNGDEC_ERROR_HEADER; } // Create a libpng structure, also pass our custom error/warning functions stream->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, pngDecError, pngDecWarning); // Check if the creation of the structure failed if (!stream->png_ptr) { cellPngDec.error("Creation of png_structp failed."); return CELL_PNGDEC_ERROR_FATAL; } // Create a libpng info structure stream->info_ptr = png_create_info_struct(stream->png_ptr); // Check if the creation of the structure failed if (!stream->info_ptr) { throw EXCEPTION("Creation of png_infop failed."); } // Set a point to return to when an error occurs in libpng if (setjmp(png_jmpbuf(stream->png_ptr))) { throw EXCEPTION("Fatal error in libpng."); } // We must indicate, that we allocated more memory open_info->initSpaceAllocated += sizeof(PngBuffer); // Init the IO for either reading from a file or a buffer if (source->srcSelect == CELL_PNGDEC_BUFFER) { // Set the data pointer and the file size buffer->length = stream->source.fileSize; buffer->data = stream->source.streamPtr; // Since we already read the header, we start reading from position 8 buffer->cursor = 8; } // Set the custom read function for decoding png_set_read_fn(stream->png_ptr, buffer.get_ptr(), pngDecReadBuffer); // We need to tell libpng, that we already read 8 bytes png_set_sig_bytes(stream->png_ptr, 8); // Read the basic info of the PNG file png_read_info(stream->png_ptr, stream->info_ptr); // Read the header info for future use stream->info.imageWidth = png_get_image_width(stream->png_ptr, stream->info_ptr); stream->info.imageHeight = png_get_image_height(stream->png_ptr, stream->info_ptr); stream->info.numComponents = png_get_channels(stream->png_ptr, stream->info_ptr); stream->info.colorSpace = getPngDecColourType(png_get_color_type(stream->png_ptr, stream->info_ptr)); stream->info.bitDepth = png_get_bit_depth(stream->png_ptr, stream->info_ptr); stream->info.interlaceMethod = png_get_interlace_type(stream->png_ptr, stream->info_ptr); stream->info.chunkInformation = pngDecGetChunkInformation(stream); return CELL_OK; }