static SquashStatus squash_brotli_decompress_buffer (SquashCodec* codec, size_t* decompressed_size, uint8_t decompressed[SQUASH_ARRAY_PARAM(*decompressed_size)], size_t compressed_size, const uint8_t compressed[SQUASH_ARRAY_PARAM(compressed_size)], SquashOptions* options) { BrotliResult res; size_t total_out = 0; size_t available_in = compressed_size; const uint8_t* next_in = compressed; size_t available_out = *decompressed_size; uint8_t* next_out = decompressed; BrotliState* s = BrotliCreateState(squash_brotli_malloc, squash_brotli_free, squash_codec_get_context (codec)); try { res = BrotliDecompressStream (&available_in, &next_in, &available_out, &next_out, &total_out, s); } catch (const std::bad_alloc& e) { (void) e; BrotliDestroyState(s); return squash_error (SQUASH_MEMORY); } catch (...) { BrotliDestroyState(s); return squash_error (SQUASH_FAILED); } BrotliDestroyState(s); *decompressed_size = total_out; return squash_brotli_status_to_squash_status (res); }
static SquashStatus squash_brotli_decompress_stream (SquashStream* stream, SquashOperation operation) { SquashBrotliStream* s = (SquashBrotliStream*) stream; if (s->finished) { return SQUASH_OK; } try { size_t total_out; BrotliResult res = BrotliDecompressStream (&s->base_object.avail_in, &s->base_object.next_in, &s->base_object.avail_out, &s->base_object.next_out, &total_out, s->decompressor); if (res == BROTLI_RESULT_SUCCESS) { s->finished = true; return SQUASH_OK; } if (SQUASH_LIKELY(res == BROTLI_RESULT_NEEDS_MORE_OUTPUT || res == BROTLI_RESULT_NEEDS_MORE_INPUT)) { return (res == BROTLI_RESULT_NEEDS_MORE_OUTPUT) ? SQUASH_PROCESSING : SQUASH_OK; } return squash_error (SQUASH_FAILED); } catch (const std::bad_alloc& e) { (void) e; return squash_error (SQUASH_MEMORY); } catch (...) { return squash_error (SQUASH_FAILED); } }
static SquashStatus squash_brotli_process_stream (SquashStream* stream, SquashOperation operation) { SquashBrotliStream* s = (SquashBrotliStream*) stream; if (stream->stream_type == SQUASH_STREAM_COMPRESS) { const int be_ret = BrotliEncoderCompressStream(s->ctx.encoder, squash_brotli_encoder_operation_from_squash_operation(operation), &(stream->avail_in), &(stream->next_in), &(stream->avail_out), &(stream->next_out), NULL); if (SQUASH_UNLIKELY(be_ret != 1)) return squash_error (SQUASH_FAILED); else if (stream->avail_in != 0 || BrotliEncoderHasMoreOutput(s->ctx.encoder)) return SQUASH_PROCESSING; else return SQUASH_OK; } else if (stream->stream_type == SQUASH_STREAM_DECOMPRESS) { const BrotliResult bd_ret = BrotliDecompressStream(&(stream->avail_in), &(stream->next_in), &(stream->avail_out), &(stream->next_out), NULL, s->ctx.decoder); switch (bd_ret) { case BROTLI_RESULT_SUCCESS: return SQUASH_OK; case BROTLI_RESULT_NEEDS_MORE_INPUT: return SQUASH_OK; case BROTLI_RESULT_NEEDS_MORE_OUTPUT: return SQUASH_PROCESSING; case BROTLI_RESULT_ERROR: return SQUASH_FAILED; } if (SQUASH_UNLIKELY(bd_ret != BROTLI_RESULT_SUCCESS)) return squash_error (SQUASH_FAILED); } else { squash_assert_unreachable (); } squash_assert_unreachable (); }
static int Decompress(FILE* fin, FILE* fout, const char* dictionary_path) { /* Dictionary should be kept during first rounds of decompression. */ uint8_t* dictionary = NULL; uint8_t* input; uint8_t* output; size_t total_out; size_t available_in; const uint8_t* next_in; size_t available_out = kFileBufferSize; uint8_t* next_out; BrotliResult result = BROTLI_RESULT_ERROR; BrotliState* s = BrotliCreateState(NULL, NULL, NULL); if (!s) { fprintf(stderr, "out of memory\n"); return 0; } if (dictionary_path != NULL) { size_t dictionary_size = 0; dictionary = ReadDictionary(dictionary_path, &dictionary_size); BrotliSetCustomDictionary(dictionary_size, dictionary, s); } input = (uint8_t*)malloc(kFileBufferSize); output = (uint8_t*)malloc(kFileBufferSize); if (!input || !output) { fprintf(stderr, "out of memory\n"); goto end; } next_out = output; result = BROTLI_RESULT_NEEDS_MORE_INPUT; while (1) { if (result == BROTLI_RESULT_NEEDS_MORE_INPUT) { if (feof(fin)) { break; } available_in = fread(input, 1, kFileBufferSize, fin); next_in = input; if (ferror(fin)) { break; } } else if (result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) { fwrite(output, 1, kFileBufferSize, fout); if (ferror(fout)) { break; } available_out = kFileBufferSize; next_out = output; } else { break; /* Error or success. */ } result = BrotliDecompressStream(&available_in, &next_in, &available_out, &next_out, &total_out, s); } if (next_out != output) { fwrite(output, 1, (size_t)(next_out - output), fout); } if ((result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) || ferror(fout)) { fprintf(stderr, "failed to write output\n"); } else if (result != BROTLI_RESULT_SUCCESS) { /* Error or needs more input. */ fprintf(stderr, "corrupt input\n"); } end: free(dictionary); free(input); free(output); BrotliDestroyState(s); return (result == BROTLI_RESULT_SUCCESS) ? 1 : 0; }
nsresult nsJARInputStream::ContinueInflate(char* aBuffer, uint32_t aCount, uint32_t* aBytesRead) { bool finished = false; // No need to check the args, ::Read did that, but assert them at least NS_ASSERTION(aBuffer,"aBuffer parameter must not be null"); NS_ASSERTION(aBytesRead,"aBytesRead parameter must not be null"); // Keep old total_out count const uint32_t oldTotalOut = mZs.total_out; // make sure we aren't reading too much mZs.avail_out = std::min(aCount, (mOutSize-oldTotalOut)); mZs.next_out = (unsigned char*)aBuffer; #ifndef MOZ_JAR_BROTLI MOZ_ASSERT(mMode == MODE_INFLATE); #endif if (mMode == MODE_INFLATE) { // now inflate int zerr = inflate(&mZs, Z_SYNC_FLUSH); if ((zerr != Z_OK) && (zerr != Z_STREAM_END)) { nsZipArchive::sFileCorruptedReason = "nsJARInputStream: error while inflating"; return NS_ERROR_FILE_CORRUPTED; } finished = (zerr == Z_STREAM_END); #ifdef MOZ_JAR_BROTLI } else { MOZ_ASSERT(mMode == MODE_BROTLI); /* The brotli library wants size_t, but z_stream only contains * unsigned int for avail_* and unsigned long for total_*. * So use temporary stack values. */ size_t avail_in = mZs.avail_in; size_t avail_out = mZs.avail_out; size_t total_out = mZs.total_out; BrotliResult result = BrotliDecompressStream( &avail_in, const_cast<const unsigned char**>(&mZs.next_in), &avail_out, &mZs.next_out, &total_out, mBrotliState); /* We don't need to update avail_out, it's not used outside this * function. */ mZs.total_out = total_out; mZs.avail_in = avail_in; if (result == BROTLI_RESULT_ERROR) { nsZipArchive::sFileCorruptedReason = "nsJARInputStream: brotli decompression error"; return NS_ERROR_FILE_CORRUPTED; } finished = (result == BROTLI_RESULT_SUCCESS); #endif } *aBytesRead = (mZs.total_out - oldTotalOut); // Calculate the CRC on the output mOutCrc = crc32(mOutCrc, (unsigned char*)aBuffer, *aBytesRead); // be aggressive about ending the inflation // for some reason we don't always get Z_STREAM_END if (finished || mZs.total_out == mOutSize) { if (mMode == MODE_INFLATE) { inflateEnd(&mZs); } // stop returning valid data as soon as we know we have a bad CRC if (mOutCrc != mInCrc) { nsZipArchive::sFileCorruptedReason = "nsJARInputStream: crc mismatch"; return NS_ERROR_FILE_CORRUPTED; } } return NS_OK; }
/** Decompresses a Brotli compressed source buffer. Extracts decompressed data to its original form. If the compressed source data specified by Source is successfully decompressed into Destination, then EFI_SUCCESS is returned. If the compressed source data specified by Source is not in a valid compressed data format, then EFI_INVALID_PARAMETER is returned. @param Source The source buffer containing the compressed data. @param SourceSize The size of source buffer. @param Destination The destination buffer to store the decompressed data. @param DestSize The destination buffer size. @param BuffInfo The pointer to the BROTLI_BUFF instance. @retval EFI_SUCCESS Decompression completed successfully, and the uncompressed buffer is returned in Destination. @retval EFI_INVALID_PARAMETER The source buffer specified by Source is corrupted (not in a valid compressed format). **/ EFI_STATUS BrotliDecompress ( IN CONST VOID* Source, IN UINTN SourceSize, IN OUT VOID* Destination, IN OUT UINTN DestSize, IN VOID * BuffInfo ) { UINT8 * Input; UINT8 * Output; const UINT8 * NextIn; UINT8 * NextOut; size_t TotalOut; size_t AvailableIn; size_t AvailableOut; BrotliResult Result; BrotliState * BroState; VOID * Temp; TotalOut = 0; AvailableOut = FILE_BUFFER_SIZE; Result = BROTLI_RESULT_ERROR; BroState = BrotliCreateState(BrAlloc, BrFree, BuffInfo); Temp = Destination; if (BroState == NULL) { return EFI_INVALID_PARAMETER; } Input = (UINT8 *)BrAlloc(BuffInfo, FILE_BUFFER_SIZE); Output = (UINT8 *)BrAlloc(BuffInfo, FILE_BUFFER_SIZE); if ((Input==NULL) || (Output==NULL)) { BrFree(BuffInfo, Input); BrFree(BuffInfo, Output); BrotliDestroyState(BroState); return EFI_INVALID_PARAMETER; } NextOut = Output; Result = BROTLI_RESULT_NEEDS_MORE_INPUT; while (1) { if (Result == BROTLI_RESULT_NEEDS_MORE_INPUT) { if (SourceSize == 0) { break; } if (SourceSize >= FILE_BUFFER_SIZE) { AvailableIn = FILE_BUFFER_SIZE; }else{ AvailableIn = SourceSize; } CopyMem(Input, Source, AvailableIn); Source = (VOID *)((UINT8 *)Source + AvailableIn); SourceSize -= AvailableIn; NextIn = Input; } else if (Result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) { CopyMem(Temp, Output, FILE_BUFFER_SIZE); AvailableOut = FILE_BUFFER_SIZE; Temp = (VOID *)((UINT8 *)Temp +FILE_BUFFER_SIZE); NextOut = Output; } else { break; /* Error or success. */ } Result = BrotliDecompressStream( &AvailableIn, &NextIn, &AvailableOut, &NextOut, &TotalOut, BroState ); } if (NextOut != Output) { CopyMem(Temp, Output, (size_t)(NextOut - Output)); } DestSize = TotalOut; BrFree(BuffInfo, Input); BrFree(BuffInfo, Output); BrotliDestroyState(BroState); return (Result == BROTLI_RESULT_SUCCESS) ? EFI_SUCCESS : EFI_INVALID_PARAMETER; }