static void read_and_hash (file_reader & reader , hasher_stream & stream , uint64_t to_read_bytes , int32_t blk_len , uint64_t t_offset , rs_mdfour_t * pctx) { // // read huge block one time and calc hash block after block length of f_blk_len; // uint32_t remain, buflen; char_buffer<uchar_t> buf (XDELTA_BUFFER_LEN); uint64_t index = 0; uint32_t size; uchar_t * rdbuf = buf.begin (); buflen = (uint32_t)(to_read_bytes > XDELTA_BUFFER_LEN ? XDELTA_BUFFER_LEN : to_read_bytes); while (to_read_bytes != 0) { size = reader.read_file (rdbuf, buflen); if (size != buflen) { std::string errmsg = fmt_string ("Can't read file %s(%s)." , reader.get_fname ().c_str (), error_msg ().c_str ()); THROW_XDELTA_EXCEPTION (errmsg); } if (pctx != 0) rs_mdfour_update(pctx, rdbuf, size); to_read_bytes -= size; const uchar_t * endbuf = rdbuf + size; rdbuf = buf.begin (); while ((int32_t)(endbuf - rdbuf) >= blk_len) { uint32_t fhash = rolling_hasher::hash (rdbuf, blk_len); struct slow_hash bsh; bsh.tpos.index = index; bsh.tpos.t_offset = t_offset; get_slow_hash (rdbuf, blk_len, bsh.hash); stream.add_block (fhash, bsh); ++index; rdbuf += blk_len; } remain = (int32_t)(endbuf - rdbuf); if (remain > 0) memmove (buf.begin (), rdbuf, remain); rdbuf = buf.begin () + remain; buflen = XDELTA_BUFFER_LEN - remain; buflen = (uint32_t)(to_read_bytes > buflen ? buflen : to_read_bytes); } }
void DLL_EXPORT get_file_digest (file_reader & reader , uchar_t digest[DIGEST_BYTES]) { const int buf_len = XDELTA_BUFFER_LEN; // four times of block. char_buffer <uchar_t> buf (XDELTA_BUFFER_LEN); rs_mdfour_t ctx; rs_mdfour_begin(&ctx); while (true) { int size = reader.read_file (buf.begin (), buf_len); if (size <= 0) break; rs_mdfour_update(&ctx, buf.begin (), size); } rs_mdfour_result (&ctx, digest); }
uint32_t seek_and_read (file_reader & reader, uint64_t offset, uint32_t length, uchar_t * data) { uint64_t s_offset = reader.seek_file (offset, FILE_BEGIN); if (offset != s_offset) { std::string errmsg = fmt_string ("Can't seek file %s(%s)." , reader.get_fname ().c_str (), error_msg ().c_str ()); THROW_XDELTA_EXCEPTION (errmsg); } uint32_t ret = reader.read_file (data, length); if (ret < length) { std::string errmsg = fmt_string ("Bytes read from %s(%s) is less than demand." , reader.get_fname ().c_str (), error_msg ().c_str ()); THROW_XDELTA_EXCEPTION (errmsg); } return ret; }
void read_and_delta (file_reader & reader , xdelta_stream & stream , const hash_table & hashes , std::set<hole_t> & hole_set , const int blk_len , bool need_split_hole) { bool adddiff = !need_split_hole; char_buffer<uchar_t> buf (XDELTA_BUFFER_LEN); typedef std::set<hole_t>::iterator it_t; std::list<hole_t> holes2remove; for (it_t begin = hole_set.begin (); begin != hole_set.end (); ++begin) { const hole_t & hole = *begin; uint64_t offset = reader.seek_file (hole.offset, FILE_BEGIN); if (offset != hole.offset) { std::string errmsg = fmt_string ("Can't seek file %s(%s)." , reader.get_fname ().c_str (), error_msg ().c_str ()); THROW_XDELTA_EXCEPTION (errmsg); } uint32_t buflen = XDELTA_BUFFER_LEN; uint32_t to_read_bytes = (uint32_t)hole.length; buflen = to_read_bytes > buflen ? buflen : to_read_bytes; uchar_t * rdbuf = buf.begin (); uint32_t size = reader.read_file (rdbuf, buflen); if (size != buflen) { std::string errmsg = fmt_string ("Can't read file %s(%s)." , reader.get_fname ().c_str (), error_msg ().c_str ()); THROW_XDELTA_EXCEPTION (errmsg); } to_read_bytes -= size; const uchar_t * endbuf = rdbuf + size; rdbuf = buf.begin (); if ((int32_t)(endbuf - rdbuf) >= blk_len) { uchar_t * sentrybuf = rdbuf; rolling_hasher hasher; hasher.eat_hash (rdbuf, blk_len); while (true) { bool newhash = false; const slow_hash * bsh = hashes.find_block (hasher.hash_value (), rdbuf, blk_len); uchar_t outchar = 0; if (bsh) { // a match was found. uint32_t slipsize = (uint32_t)(rdbuf - sentrybuf); if (slipsize > 0 && adddiff) stream.add_block (sentrybuf, slipsize, offset); offset += slipsize; stream.add_block (bsh->tpos, blk_len, offset); if (need_split_hole) { hole_t newhole; newhole.offset = offset; newhole.length = blk_len; holes2remove.push_back (newhole); } rdbuf += blk_len; sentrybuf = rdbuf; newhash = true; offset += blk_len; } else { // slip the window by one bytes which size is blk_len. outchar = *rdbuf; ++rdbuf; } // // beyond the buffer. int remain = (int)(endbuf - rdbuf); if (remain < blk_len) { if (to_read_bytes == 0) { // no more to read. uint32_t slipsize = (uint32_t)(endbuf - sentrybuf); if (slipsize > 0 && adddiff) stream.add_block (sentrybuf, slipsize, offset); goto end; } else { memmove (buf.begin (), rdbuf, remain); rdbuf = buf.begin (); sentrybuf = rdbuf; buflen = XDELTA_BUFFER_LEN - remain; buflen = to_read_bytes > buflen ? buflen : to_read_bytes; size = reader.read_file (rdbuf + remain, buflen); if (size != buflen) { std::string errmsg = fmt_string ("Can't read file %s(%s)." , reader.get_fname ().c_str (), error_msg ().c_str ()); THROW_XDELTA_EXCEPTION (errmsg); } to_read_bytes -= size; endbuf = rdbuf + remain + size; remain += size; if (remain >= blk_len) { if (newhash) hasher.eat_hash (rdbuf, blk_len); else hasher.update (outchar, *(rdbuf + blk_len)); } else { // // one read must complement data which length plus // remain must be more than one block length of @f_blk_len, // so if remain less than that, it must be reach the end of // file // if (adddiff) stream.add_block (rdbuf, remain, offset); offset += remain; goto end; } } } else { if (newhash) hasher.eat_hash (rdbuf, blk_len); else hasher.update (outchar, *(rdbuf + blk_len - 1)); } } } else { if (adddiff) stream.add_block (rdbuf, size, offset); } end: continue; } if (need_split_hole) { typedef std::list<hole_t>::iterator it_t; for (it_t begin = holes2remove.begin (); begin != holes2remove.end (); ++begin) split_hole (hole_set, *begin); } return; }