void TargaLoader::read_image_data() { image_data = DataBuffer(bytes_per_pixel_entry * image_width * image_height); if (image_type == 9 || image_type == 10 || image_type == 11) // RLE compressed { DataBuffer rle_data(file.get_size() - file.get_position()); file.read(rle_data.get_data(), rle_data.get_size()); unsigned char *input = reinterpret_cast<unsigned char*>(rle_data.get_data()); unsigned char *output = reinterpret_cast<unsigned char*>(image_data.get_data()); int pixels_left = image_width * image_height; int input_available = rle_data.get_size(); while (pixels_left > 0 && input_available > 0) { int code = *input; int count = (code & 0x7f) + 1; bool rle_packet = (code & 0x80) != 0; input++; input_available--; if (rle_packet) { if (bytes_per_pixel_entry > input_available && pixels_left >= count) // Check for buffer overruns break; for (int i = 0; i < count; i++) memcpy(output + i * bytes_per_pixel_entry, input, bytes_per_pixel_entry); input += bytes_per_pixel_entry; } else { if (count * bytes_per_pixel_entry >= input_available && pixels_left >= count) // Check for buffer overruns break; memcpy(output, input, count * bytes_per_pixel_entry); input += count * bytes_per_pixel_entry; } output += bytes_per_pixel_entry * count; pixels_left -= count; } } else { file.read(image_data.get_data(), image_data.get_size()); } }
huffman_error huffman_context_base::export_tree_huffman(bitstream_out &bitbuf) { // first RLE compress the lengths of all the nodes dynamic_buffer rle_data(m_numcodes); UINT8 *dest = &rle_data[0]; std::vector<UINT16> rle_lengths(m_numcodes/3); UINT16 *lengths = &rle_lengths[0]; int last = ~0; int repcount = 0; // use a small huffman context to create a tree (ignoring RLE lengths) huffman_encoder<24, 6> smallhuff; // RLE-compress the lengths for (int curcode = 0; curcode < m_numcodes; curcode++) { // if this is the end of a repeat, flush any accumulation int newval = m_huffnode[curcode].m_numbits; if (newval != last && repcount > 0) { if (repcount == 1) smallhuff.histo_one(*dest++ = last + 1); else smallhuff.histo_one(*dest++ = 0), *lengths++ = repcount - 2; } // if same as last, just track repeats if (newval == last) repcount++; // otherwise, write it and start a new run else { smallhuff.histo_one(*dest++ = newval + 1); last = newval; repcount = 0; } } // flush any final RLE counts if (repcount > 0) { if (repcount == 1) smallhuff.histo_one(*dest++ = last + 1); else smallhuff.histo_one(*dest++ = 0), *lengths++ = repcount - 2; } // compute an optimal tree smallhuff.compute_tree_from_histo(); // determine the first and last non-zero nodes int first_non_zero = 31, last_non_zero = 0; for (int index = 1; index < smallhuff.m_numcodes; index++) if (smallhuff.m_huffnode[index].m_numbits != 0) { if (first_non_zero == 31) first_non_zero = index; last_non_zero = index; } // clamp first non-zero to be 8 at a maximum first_non_zero = MIN(first_non_zero, 8); // output the lengths of the each small tree node, starting with the RLE // token (0), followed by the first_non_zero value, followed by the data // terminated by a 7 bitbuf.write(smallhuff.m_huffnode[0].m_numbits, 3); bitbuf.write(first_non_zero - 1, 3); for (int index = first_non_zero; index <= last_non_zero; index++) bitbuf.write(smallhuff.m_huffnode[index].m_numbits, 3); bitbuf.write(7, 3); // determine the maximum length of an RLE count UINT32 temp = m_numcodes - 9; UINT8 rlefullbits = 0; while (temp != 0) temp >>= 1, rlefullbits++; // now encode the RLE data lengths = &rle_lengths[0]; for (UINT8 *src = &rle_data[0]; src < dest; src++) { // encode the data UINT8 data = *src; smallhuff.encode_one(bitbuf, data); // if this is an RLE token, encode the length following if (data == 0) { int count = *lengths++; if (count < 7) bitbuf.write(count, 3); else bitbuf.write(7, 3), bitbuf.write(count - 7, rlefullbits); } } // flush the final buffer return bitbuf.overflow() ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE; }