qemu/xbzrle.c
<<
>>
Prefs
   1/*
   2 * Xor Based Zero Run Length Encoding
   3 *
   4 * Copyright 2013 Red Hat, Inc. and/or its affiliates
   5 *
   6 * Authors:
   7 *  Orit Wasserman  <owasserm@redhat.com>
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 *
  12 */
  13#include "qemu-common.h"
  14#include "include/migration/migration.h"
  15
  16/*
  17  page = zrun nzrun
  18       | zrun nzrun page
  19
  20  zrun = length
  21
  22  nzrun = length byte...
  23
  24  length = uleb128 encoded integer
  25 */
  26int xbzrle_encode_buffer(uint8_t *old_buf, uint8_t *new_buf, int slen,
  27                         uint8_t *dst, int dlen)
  28{
  29    uint32_t zrun_len = 0, nzrun_len = 0;
  30    int d = 0, i = 0;
  31    long res, xor;
  32    uint8_t *nzrun_start = NULL;
  33
  34    g_assert(!(((uintptr_t)old_buf | (uintptr_t)new_buf | slen) %
  35               sizeof(long)));
  36
  37    while (i < slen) {
  38        /* overflow */
  39        if (d + 2 > dlen) {
  40            return -1;
  41        }
  42
  43        /* not aligned to sizeof(long) */
  44        res = (slen - i) % sizeof(long);
  45        while (res && old_buf[i] == new_buf[i]) {
  46            zrun_len++;
  47            i++;
  48            res--;
  49        }
  50
  51        /* word at a time for speed */
  52        if (!res) {
  53            while (i < slen &&
  54                   (*(long *)(old_buf + i)) == (*(long *)(new_buf + i))) {
  55                i += sizeof(long);
  56                zrun_len += sizeof(long);
  57            }
  58
  59            /* go over the rest */
  60            while (i < slen && old_buf[i] == new_buf[i]) {
  61                zrun_len++;
  62                i++;
  63            }
  64        }
  65
  66        /* buffer unchanged */
  67        if (zrun_len == slen) {
  68            return 0;
  69        }
  70
  71        /* skip last zero run */
  72        if (i == slen) {
  73            return d;
  74        }
  75
  76        d += uleb128_encode_small(dst + d, zrun_len);
  77
  78        zrun_len = 0;
  79        nzrun_start = new_buf + i;
  80
  81        /* overflow */
  82        if (d + 2 > dlen) {
  83            return -1;
  84        }
  85        /* not aligned to sizeof(long) */
  86        res = (slen - i) % sizeof(long);
  87        while (res && old_buf[i] != new_buf[i]) {
  88            i++;
  89            nzrun_len++;
  90            res--;
  91        }
  92
  93        /* word at a time for speed, use of 32-bit long okay */
  94        if (!res) {
  95            /* truncation to 32-bit long okay */
  96            long mask = (long)0x0101010101010101ULL;
  97            while (i < slen) {
  98                xor = *(long *)(old_buf + i) ^ *(long *)(new_buf + i);
  99                if ((xor - mask) & ~xor & (mask << 7)) {
 100                    /* found the end of an nzrun within the current long */
 101                    while (old_buf[i] != new_buf[i]) {
 102                        nzrun_len++;
 103                        i++;
 104                    }
 105                    break;
 106                } else {
 107                    i += sizeof(long);
 108                    nzrun_len += sizeof(long);
 109                }
 110            }
 111        }
 112
 113        d += uleb128_encode_small(dst + d, nzrun_len);
 114        /* overflow */
 115        if (d + nzrun_len > dlen) {
 116            return -1;
 117        }
 118        memcpy(dst + d, nzrun_start, nzrun_len);
 119        d += nzrun_len;
 120        nzrun_len = 0;
 121    }
 122
 123    return d;
 124}
 125
 126int xbzrle_decode_buffer(uint8_t *src, int slen, uint8_t *dst, int dlen)
 127{
 128    int i = 0, d = 0;
 129    int ret;
 130    uint32_t count = 0;
 131
 132    while (i < slen) {
 133
 134        /* zrun */
 135        if ((slen - i) < 2) {
 136            return -1;
 137        }
 138
 139        ret = uleb128_decode_small(src + i, &count);
 140        if (ret < 0 || (i && !count)) {
 141            return -1;
 142        }
 143        i += ret;
 144        d += count;
 145
 146        /* overflow */
 147        if (d > dlen) {
 148            return -1;
 149        }
 150
 151        /* nzrun */
 152        if ((slen - i) < 2) {
 153            return -1;
 154        }
 155
 156        ret = uleb128_decode_small(src + i, &count);
 157        if (ret < 0 || !count) {
 158            return -1;
 159        }
 160        i += ret;
 161
 162        /* overflow */
 163        if (d + count > dlen || i + count > slen) {
 164            return -1;
 165        }
 166
 167        memcpy(dst + d, src + i, count);
 168        d += count;
 169        i += count;
 170    }
 171
 172    return d;
 173}
 174