static void input_handle_th(void *p) { char c; int b = 0; setsockopt(ihpipe[1], SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); while (1) if (read(0, &c, 1) == 1) be_write(ihpipe[1], &c, 1); }
static void be_write_list(struct be_list *list, FILE *out) { size_t i; fputc('l', out); for(i = 0; i < list->len; i++) { be_write(list->nodes + i, out); } fputc('e', out); }
static void be_write_dict(struct be_dict *dict, FILE *out) { fputc('d', out); size_t i; for(i = 0; i < dict->len; i++) { struct be_str *bstr = dict->pairs[i].key; be_write_str(bstr, out); be_write(dict->pairs[i].val, out); } fputc('e', out); }
void chd_file::decompress_v5_map() { // if no offset, we haven't written it yet if (m_mapoffset == 0) { memset(m_rawmap, 0xff, m_rawmap.count()); return; } // read the reader UINT8 rawbuf[16]; file_read(m_mapoffset, rawbuf, sizeof(rawbuf)); UINT32 mapbytes = be_read(&rawbuf[0], 4); UINT64 firstoffs = be_read(&rawbuf[4], 6); UINT16 mapcrc = be_read(&rawbuf[10], 2); UINT8 lengthbits = rawbuf[12]; UINT8 selfbits = rawbuf[13]; UINT8 parentbits = rawbuf[14]; // now read the map dynamic_buffer compressed(mapbytes); file_read(m_mapoffset + 16, compressed, mapbytes); bitstream_in bitbuf(compressed, compressed.count()); // first decode the compression types huffman_decoder<16, 8> decoder; huffman_error err = decoder.import_tree_rle(bitbuf); if (err != HUFFERR_NONE) throw CHDERR_DECOMPRESSION_ERROR; UINT8 lastcomp = 0; int repcount = 0; for (int hunknum = 0; hunknum < m_hunkcount; hunknum++) { UINT8 *rawmap = &m_rawmap[hunknum * 12]; if (repcount > 0) rawmap[0] = lastcomp, repcount--; else { UINT8 val = decoder.decode_one(bitbuf); if (val == COMPRESSION_RLE_SMALL) rawmap[0] = lastcomp, repcount = 2 + decoder.decode_one(bitbuf); else if (val == COMPRESSION_RLE_LARGE) rawmap[0] = lastcomp, repcount = 2 + 16 + (decoder.decode_one(bitbuf) << 4), repcount += decoder.decode_one(bitbuf); else rawmap[0] = lastcomp = val; } } // then iterate through the hunks and extract the needed data UINT64 curoffset = firstoffs; UINT32 last_self = 0; UINT64 last_parent = 0; for (int hunknum = 0; hunknum < m_hunkcount; hunknum++) { UINT8 *rawmap = &m_rawmap[hunknum * 12]; UINT64 offset = curoffset; UINT32 length = 0; UINT16 crc = 0; switch (rawmap[0]) { // base types case COMPRESSION_TYPE_0: case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_2: case COMPRESSION_TYPE_3: curoffset += length = bitbuf.read(lengthbits); crc = bitbuf.read(16); break; case COMPRESSION_NONE: curoffset += length = m_hunkbytes; crc = bitbuf.read(16); break; case COMPRESSION_SELF: last_self = offset = bitbuf.read(selfbits); break; case COMPRESSION_PARENT: offset = bitbuf.read(parentbits); last_parent = offset; break; // pseudo-types; convert into base types case COMPRESSION_SELF_1: last_self++; case COMPRESSION_SELF_0: rawmap[0] = COMPRESSION_SELF; offset = last_self; break; case COMPRESSION_PARENT_SELF: rawmap[0] = COMPRESSION_PARENT; last_parent = offset = (UINT64(hunknum) * UINT64(m_hunkbytes)) / m_unitbytes; break; case COMPRESSION_PARENT_1: last_parent += m_hunkbytes / m_unitbytes; case COMPRESSION_PARENT_0: rawmap[0] = COMPRESSION_PARENT; offset = last_parent; break; } be_write(&rawmap[1], length, 3); be_write(&rawmap[4], offset, 6); be_write(&rawmap[10], crc, 2); } // verify the final CRC if (crc16_creator::simple(m_rawmap, m_hunkcount * 12) != mapcrc) throw CHDERR_DECOMPRESSION_ERROR; }
chd_error chd_file::read_hunk(UINT32 hunknum, void *buffer) { // wrap this for clean reporting try { // punt if no file if (m_file == NULL) throw CHDERR_NOT_OPEN; // return an error if out of range if (hunknum >= m_hunkcount) throw CHDERR_HUNK_OUT_OF_RANGE; // get a pointer to the map entry UINT64 blockoffs; UINT32 blocklen; UINT32 blockcrc; UINT8 *rawmap; UINT8 *dest = reinterpret_cast<UINT8 *>(buffer); switch (m_version) { // v3/v4 map entries case 3: case 4: rawmap = m_rawmap + 16 * hunknum; blockoffs = be_read(&rawmap[0], 8); blockcrc = be_read(&rawmap[8], 4); switch (rawmap[15] & V34_MAP_ENTRY_FLAG_TYPE_MASK) { case V34_MAP_ENTRY_TYPE_COMPRESSED: blocklen = be_read(&rawmap[12], 2) + (rawmap[14] << 16); file_read(blockoffs, m_compressed, blocklen); m_decompressor[0]->decompress(m_compressed, blocklen, dest, m_hunkbytes); if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && dest != NULL && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case V34_MAP_ENTRY_TYPE_UNCOMPRESSED: file_read(blockoffs, dest, m_hunkbytes); if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case V34_MAP_ENTRY_TYPE_MINI: be_write(dest, blockoffs, 8); for (UINT32 bytes = 8; bytes < m_hunkbytes; bytes++) dest[bytes] = dest[bytes - 8]; if (!(rawmap[15] & V34_MAP_ENTRY_FLAG_NO_CRC) && crc32_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case V34_MAP_ENTRY_TYPE_SELF_HUNK: return read_hunk(blockoffs, dest); case V34_MAP_ENTRY_TYPE_PARENT_HUNK: if (m_parent_missing) throw CHDERR_REQUIRES_PARENT; return m_parent->read_hunk(blockoffs, dest); } break; // v5 map entries case 5: rawmap = m_rawmap + m_mapentrybytes * hunknum; // uncompressed case if (!compressed()) { blockoffs = UINT64(be_read(rawmap, 4)) * UINT64(m_hunkbytes); if (blockoffs != 0) file_read(blockoffs, dest, m_hunkbytes); else if (m_parent_missing) throw CHDERR_REQUIRES_PARENT; else if (m_parent != NULL) m_parent->read_hunk(hunknum, dest); else memset(dest, 0, m_hunkbytes); return CHDERR_NONE; } // compressed case blocklen = be_read(&rawmap[1], 3); blockoffs = be_read(&rawmap[4], 6); blockcrc = be_read(&rawmap[10], 2); switch (rawmap[0]) { case COMPRESSION_TYPE_0: case COMPRESSION_TYPE_1: case COMPRESSION_TYPE_2: case COMPRESSION_TYPE_3: file_read(blockoffs, m_compressed, blocklen); m_decompressor[rawmap[0]]->decompress(m_compressed, blocklen, dest, m_hunkbytes); if (!m_decompressor[rawmap[0]]->lossy() && dest != NULL && crc16_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; if (m_decompressor[rawmap[0]]->lossy() && crc16_creator::simple(m_compressed, blocklen) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case COMPRESSION_NONE: file_read(blockoffs, dest, m_hunkbytes); if (crc16_creator::simple(dest, m_hunkbytes) != blockcrc) throw CHDERR_DECOMPRESSION_ERROR; return CHDERR_NONE; case COMPRESSION_SELF: return read_hunk(blockoffs, dest); case COMPRESSION_PARENT: if (m_parent_missing) throw CHDERR_REQUIRES_PARENT; return m_parent->read_bytes(UINT64(blockoffs) * UINT64(m_parent->unit_bytes()), dest, m_hunkbytes); } break; } // if we get here, something was wrong throw CHDERR_READ_ERROR; } // just return errors catch (chd_error &err) { return err; } }