tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lz4file.c (9359B)


      1 /*
      2 * LZ4 file library
      3 * Copyright (C) 2022, Xiaomi Inc.
      4 *
      5 * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
      6 *
      7 * Redistribution and use in source and binary forms, with or without
      8 * modification, are permitted provided that the following conditions are
      9 * met:
     10 *
     11 * - Redistributions of source code must retain the above copyright
     12 *   notice, this list of conditions and the following disclaimer.
     13 * - Redistributions in binary form must reproduce the above
     14 *   copyright notice, this list of conditions and the following disclaimer
     15 *   in the documentation and/or other materials provided with the
     16 *   distribution.
     17 *
     18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 *
     30 * You can contact the author at :
     31 * - LZ4 homepage : http://www.lz4.org
     32 * - LZ4 source repository : https://github.com/lz4/lz4
     33 */
     34 #include <stdlib.h>  /* malloc, free */
     35 #include <string.h>
     36 #include <assert.h>
     37 #include "lz4.h"
     38 #include "lz4file.h"
     39 
     40 static LZ4F_errorCode_t returnErrorCode(LZ4F_errorCodes code)
     41 {
     42    return (LZ4F_errorCode_t)-(ptrdiff_t)code;
     43 }
     44 #undef RETURN_ERROR
     45 #define RETURN_ERROR(e) return returnErrorCode(LZ4F_ERROR_ ## e)
     46 
     47 /* =====   read API   ===== */
     48 
     49 struct LZ4_readFile_s {
     50  LZ4F_dctx* dctxPtr;
     51  FILE* fp;
     52  LZ4_byte* srcBuf;
     53  size_t srcBufNext;
     54  size_t srcBufSize;
     55  size_t srcBufMaxSize;
     56 };
     57 
     58 static void LZ4F_freeReadFile(LZ4_readFile_t* lz4fRead)
     59 {
     60  if (lz4fRead==NULL) return;
     61  LZ4F_freeDecompressionContext(lz4fRead->dctxPtr);
     62  free(lz4fRead->srcBuf);
     63  free(lz4fRead);
     64 }
     65 
     66 static void LZ4F_freeAndNullReadFile(LZ4_readFile_t** statePtr)
     67 {
     68  assert(statePtr != NULL);
     69  LZ4F_freeReadFile(*statePtr);
     70  *statePtr = NULL;
     71 }
     72 
     73 LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp)
     74 {
     75  char buf[LZ4F_HEADER_SIZE_MAX];
     76  size_t consumedSize;
     77  LZ4F_errorCode_t ret;
     78 
     79  if (fp == NULL || lz4fRead == NULL) {
     80    RETURN_ERROR(parameter_null);
     81  }
     82 
     83  *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t));
     84  if (*lz4fRead == NULL) {
     85    RETURN_ERROR(allocation_failed);
     86  }
     87 
     88  ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_VERSION);
     89  if (LZ4F_isError(ret)) {
     90    LZ4F_freeAndNullReadFile(lz4fRead);
     91    return ret;
     92  }
     93 
     94  (*lz4fRead)->fp = fp;
     95  consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp);
     96  if (consumedSize != sizeof(buf)) {
     97    LZ4F_freeAndNullReadFile(lz4fRead);
     98    RETURN_ERROR(io_read);
     99  }
    100 
    101  { LZ4F_frameInfo_t info;
    102    LZ4F_errorCode_t const r = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize);
    103    if (LZ4F_isError(r)) {
    104      LZ4F_freeAndNullReadFile(lz4fRead);
    105      return r;
    106    }
    107 
    108    switch (info.blockSizeID) {
    109      case LZ4F_default :
    110      case LZ4F_max64KB :
    111        (*lz4fRead)->srcBufMaxSize = 64 * 1024;
    112        break;
    113      case LZ4F_max256KB:
    114        (*lz4fRead)->srcBufMaxSize = 256 * 1024;
    115        break;
    116      case LZ4F_max1MB:
    117        (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024;
    118        break;
    119      case LZ4F_max4MB:
    120        (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024;
    121        break;
    122      default:
    123        LZ4F_freeAndNullReadFile(lz4fRead);
    124        RETURN_ERROR(maxBlockSize_invalid);
    125    }
    126  }
    127 
    128  (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize);
    129  if ((*lz4fRead)->srcBuf == NULL) {
    130    LZ4F_freeAndNullReadFile(lz4fRead);
    131    RETURN_ERROR(allocation_failed);
    132  }
    133 
    134  (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize;
    135  memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize);
    136 
    137  return ret;
    138 }
    139 
    140 size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size)
    141 {
    142  LZ4_byte* p = (LZ4_byte*)buf;
    143  size_t next = 0;
    144 
    145  if (lz4fRead == NULL || buf == NULL)
    146    RETURN_ERROR(parameter_null);
    147 
    148  while (next < size) {
    149    size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext;
    150    size_t dstsize = size - next;
    151    size_t ret;
    152 
    153    if (srcsize == 0) {
    154      ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp);
    155      if (ret > 0) {
    156        lz4fRead->srcBufSize = ret;
    157        srcsize = lz4fRead->srcBufSize;
    158        lz4fRead->srcBufNext = 0;
    159      } else if (ret == 0) {
    160        break;
    161      } else {
    162        RETURN_ERROR(io_read);
    163      }
    164    }
    165 
    166    ret = LZ4F_decompress(lz4fRead->dctxPtr,
    167                          p, &dstsize,
    168                          lz4fRead->srcBuf + lz4fRead->srcBufNext,
    169                          &srcsize,
    170                          NULL);
    171    if (LZ4F_isError(ret)) {
    172        return ret;
    173    }
    174 
    175    lz4fRead->srcBufNext += srcsize;
    176    next += dstsize;
    177    p += dstsize;
    178  }
    179 
    180  return next;
    181 }
    182 
    183 LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead)
    184 {
    185  if (lz4fRead == NULL)
    186    RETURN_ERROR(parameter_null);
    187  LZ4F_freeReadFile(lz4fRead);
    188  return LZ4F_OK_NoError;
    189 }
    190 
    191 /* =====   write API   ===== */
    192 
    193 struct LZ4_writeFile_s {
    194  LZ4F_cctx* cctxPtr;
    195  FILE* fp;
    196  LZ4_byte* dstBuf;
    197  size_t maxWriteSize;
    198  size_t dstBufMaxSize;
    199  LZ4F_errorCode_t errCode;
    200 };
    201 
    202 static void LZ4F_freeWriteFile(LZ4_writeFile_t* state)
    203 {
    204  if (state == NULL) return;
    205  LZ4F_freeCompressionContext(state->cctxPtr);
    206  free(state->dstBuf);
    207  free(state);
    208 }
    209 
    210 static void LZ4F_freeAndNullWriteFile(LZ4_writeFile_t** statePtr)
    211 {
    212  assert(statePtr != NULL);
    213  LZ4F_freeWriteFile(*statePtr);
    214  *statePtr = NULL;
    215 }
    216 
    217 LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr)
    218 {
    219  LZ4_byte buf[LZ4F_HEADER_SIZE_MAX];
    220  size_t ret;
    221 
    222  if (fp == NULL || lz4fWrite == NULL)
    223    RETURN_ERROR(parameter_null);
    224 
    225  *lz4fWrite = (LZ4_writeFile_t*)calloc(1, sizeof(LZ4_writeFile_t));
    226  if (*lz4fWrite == NULL) {
    227    RETURN_ERROR(allocation_failed);
    228  }
    229  if (prefsPtr != NULL) {
    230    switch (prefsPtr->frameInfo.blockSizeID) {
    231      case LZ4F_default :
    232      case LZ4F_max64KB :
    233        (*lz4fWrite)->maxWriteSize = 64 * 1024;
    234        break;
    235      case LZ4F_max256KB:
    236        (*lz4fWrite)->maxWriteSize = 256 * 1024;
    237        break;
    238      case LZ4F_max1MB:
    239        (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024;
    240        break;
    241      case LZ4F_max4MB:
    242        (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024;
    243        break;
    244      default:
    245        LZ4F_freeAndNullWriteFile(lz4fWrite);
    246        RETURN_ERROR(maxBlockSize_invalid);
    247      }
    248    } else {
    249      (*lz4fWrite)->maxWriteSize = 64 * 1024;
    250    }
    251 
    252  (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr);
    253  (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize);
    254  if ((*lz4fWrite)->dstBuf == NULL) {
    255    LZ4F_freeAndNullWriteFile(lz4fWrite);
    256    RETURN_ERROR(allocation_failed);
    257  }
    258 
    259  ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_VERSION);
    260  if (LZ4F_isError(ret)) {
    261      LZ4F_freeAndNullWriteFile(lz4fWrite);
    262      return ret;
    263  }
    264 
    265  ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr);
    266  if (LZ4F_isError(ret)) {
    267      LZ4F_freeAndNullWriteFile(lz4fWrite);
    268      return ret;
    269  }
    270 
    271  if (ret != fwrite(buf, 1, ret, fp)) {
    272    LZ4F_freeAndNullWriteFile(lz4fWrite);
    273    RETURN_ERROR(io_write);
    274  }
    275 
    276  (*lz4fWrite)->fp = fp;
    277  (*lz4fWrite)->errCode = LZ4F_OK_NoError;
    278  return LZ4F_OK_NoError;
    279 }
    280 
    281 size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, const void* buf, size_t size)
    282 {
    283  const LZ4_byte* p = (const LZ4_byte*)buf;
    284  size_t remain = size;
    285  size_t chunk;
    286  size_t ret;
    287 
    288  if (lz4fWrite == NULL || buf == NULL)
    289    RETURN_ERROR(parameter_null);
    290  while (remain) {
    291    if (remain > lz4fWrite->maxWriteSize)
    292      chunk = lz4fWrite->maxWriteSize;
    293    else
    294      chunk = remain;
    295 
    296    ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr,
    297                              lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
    298                              p, chunk,
    299                              NULL);
    300    if (LZ4F_isError(ret)) {
    301      lz4fWrite->errCode = ret;
    302      return ret;
    303    }
    304 
    305    if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
    306      lz4fWrite->errCode = returnErrorCode(LZ4F_ERROR_io_write);
    307      RETURN_ERROR(io_write);
    308    }
    309 
    310    p += chunk;
    311    remain -= chunk;
    312  }
    313 
    314  return size;
    315 }
    316 
    317 LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite)
    318 {
    319  LZ4F_errorCode_t ret = LZ4F_OK_NoError;
    320 
    321  if (lz4fWrite == NULL) {
    322    RETURN_ERROR(parameter_null);
    323  }
    324 
    325  if (lz4fWrite->errCode == LZ4F_OK_NoError) {
    326    ret =  LZ4F_compressEnd(lz4fWrite->cctxPtr,
    327                            lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
    328                            NULL);
    329    if (LZ4F_isError(ret)) {
    330      goto out;
    331    }
    332 
    333    if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
    334      ret = returnErrorCode(LZ4F_ERROR_io_write);
    335    }
    336  }
    337 
    338 out:
    339  LZ4F_freeWriteFile(lz4fWrite);
    340  return ret;
    341 }