Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Snappy decompression algorithm
  3.  * Copyright (c) 2015 Luca Barbato
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. #include "libavutil/mem.h"
  23.  
  24. #include "bytestream.h"
  25. #include "snappy.h"
  26.  
  27. enum {
  28.     SNAPPY_LITERAL,
  29.     SNAPPY_COPY_1,
  30.     SNAPPY_COPY_2,
  31.     SNAPPY_COPY_4,
  32. };
  33.  
  34. static int64_t bytestream2_get_levarint(GetByteContext *gb)
  35. {
  36.     uint64_t val = 0;
  37.     int shift = 0;
  38.     int tmp;
  39.  
  40.     do {
  41.         tmp = bytestream2_get_byte(gb);
  42.         val |= (tmp & 127) << shift;
  43.         shift += 7;
  44.     } while (tmp & 128);
  45.  
  46.     return val;
  47. }
  48.  
  49. static int snappy_literal(GetByteContext *gb, uint8_t *p, int size, int val)
  50. {
  51.     unsigned int len = 1;
  52.  
  53.     switch (val) {
  54.     case 63:
  55.         len += bytestream2_get_le32(gb);
  56.         break;
  57.     case 62:
  58.         len += bytestream2_get_le24(gb);
  59.         break;
  60.     case 61:
  61.         len += bytestream2_get_le16(gb);
  62.         break;
  63.     case 60:
  64.         len += bytestream2_get_byte(gb);
  65.         break;
  66.     default: // val < 60
  67.         len += val;
  68.     }
  69.  
  70.     if (size < len)
  71.         return AVERROR_INVALIDDATA;
  72.  
  73.     bytestream2_get_buffer(gb, p, len);
  74.  
  75.     return len;
  76. }
  77.  
  78. static int snappy_copy(uint8_t *start, uint8_t *p, int size,
  79.                        unsigned int off, int len)
  80. {
  81.     uint8_t *q;
  82.     int i;
  83.     if (off > p - start || size < len)
  84.         return AVERROR_INVALIDDATA;
  85.  
  86.     q = p - off;
  87.  
  88.     for (i = 0; i < len; i++)
  89.         p[i] = q[i];
  90.  
  91.     return len;
  92. }
  93.  
  94. static int snappy_copy1(GetByteContext *gb, uint8_t *start, uint8_t *p,
  95.                         int size, int val)
  96. {
  97.     int len          = 4 + (val & 0x7);
  98.     unsigned int off = bytestream2_get_byte(gb) | (val & 0x38) << 5;
  99.  
  100.     return snappy_copy(start, p, size, off, len);
  101. }
  102.  
  103. static int snappy_copy2(GetByteContext *gb, uint8_t *start, uint8_t *p,
  104.                         int size, int val)
  105. {
  106.     int len          = 1 + val;
  107.     unsigned int off = bytestream2_get_le16(gb);
  108.  
  109.     return snappy_copy(start, p, size, off, len);
  110. }
  111.  
  112. static int snappy_copy4(GetByteContext *gb, uint8_t *start, uint8_t *p,
  113.                         int size, int val)
  114. {
  115.     int len          = 1 + val;
  116.     unsigned int off = bytestream2_get_le32(gb);
  117.  
  118.     return snappy_copy(start, p, size, off, len);
  119. }
  120.  
  121. static int64_t decode_len(GetByteContext *gb)
  122. {
  123.     int64_t len = bytestream2_get_levarint(gb);
  124.  
  125.     if (len < 0 || len > UINT_MAX)
  126.         return AVERROR_INVALIDDATA;
  127.  
  128.     return len;
  129. }
  130.  
  131. int64_t ff_snappy_peek_uncompressed_length(GetByteContext *gb)
  132. {
  133.     int pos = bytestream2_get_bytes_left(gb);
  134.     int64_t len = decode_len(gb);
  135.  
  136.     bytestream2_seek(gb, -pos, SEEK_END);
  137.  
  138.     return len;
  139. }
  140.  
  141. int ff_snappy_uncompress(GetByteContext *gb, uint8_t *buf, int64_t *size)
  142. {
  143.     int64_t len = decode_len(gb);
  144.     int ret     = 0;
  145.     uint8_t *p;
  146.  
  147.     if (len < 0)
  148.         return len;
  149.  
  150.     if (len > *size)
  151.         return AVERROR_BUFFER_TOO_SMALL;
  152.  
  153.     *size = len;
  154.     p     = buf;
  155.  
  156.     while (bytestream2_get_bytes_left(gb) > 0) {
  157.         uint8_t s = bytestream2_get_byte(gb);
  158.         int val   = s >> 2;
  159.  
  160.         switch (s & 0x03) {
  161.         case SNAPPY_LITERAL:
  162.             ret = snappy_literal(gb, p, len, val);
  163.             break;
  164.         case SNAPPY_COPY_1:
  165.             ret = snappy_copy1(gb, buf, p, len, val);
  166.             break;
  167.         case SNAPPY_COPY_2:
  168.             ret = snappy_copy2(gb, buf, p, len, val);
  169.             break;
  170.         case SNAPPY_COPY_4:
  171.             ret = snappy_copy4(gb, buf, p, len, val);
  172.             break;
  173.         }
  174.  
  175.         if (ret < 0)
  176.             return ret;
  177.  
  178.         p   += ret;
  179.         len -= ret;
  180.     }
  181.  
  182.     return 0;
  183. }
  184.