1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/* 2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2015 Google Inc. 3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * 4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be 5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file. 6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "Test.h" 9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_SUPPORT_PDF 11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkDeflate.h" 13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRandom.h" 14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotnamespace { 16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "zlib.h" 18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// Different zlib implementations use different T. 20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// We've seen size_t and unsigned. 21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottemplate <typename T> void* skia_alloc_func(void*, T items, T size) { 22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return sk_calloc_throw(SkToSizeT(items) * SkToSizeT(size)); 23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid skia_free_func(void*, void* address) { sk_free(address); } 26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/** 28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use the un-deflate compression algorithm to decompress the data in src, 29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * returning the result. Returns nullptr if an error occurs. 30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */ 31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstd::unique_ptr<SkStreamAsset> stream_inflate(skiatest::Reporter* reporter, SkStream* src) { 32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream decompressedDynamicMemoryWStream; 33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkWStream* dst = &decompressedDynamicMemoryWStream; 34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot static const size_t kBufferSize = 1024; 36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint8_t inputBuffer[kBufferSize]; 37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint8_t outputBuffer[kBufferSize]; 38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot z_stream flateData; 39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.zalloc = &skia_alloc_func; 40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.zfree = &skia_free_func; 41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.opaque = nullptr; 42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.next_in = nullptr; 43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.avail_in = 0; 44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.next_out = outputBuffer; 45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.avail_out = kBufferSize; 46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot int rc; 47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot rc = inflateInit(&flateData); 48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (rc != Z_OK) { 49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(reporter, "Zlib: inflateInit failed"); 50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint8_t* input = (uint8_t*)src->getMemoryBase(); 53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t inputLength = src->getLength(); 54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (input == nullptr || inputLength == 0) { 55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot input = nullptr; 56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.next_in = inputBuffer; 57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.avail_in = 0; 58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } else { 59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.next_in = input; 60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.avail_in = SkToUInt(inputLength); 61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot rc = Z_OK; 64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (true) { 65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (flateData.avail_out < kBufferSize) { 66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) { 67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot rc = Z_BUF_ERROR; 68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.next_out = outputBuffer; 71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.avail_out = kBufferSize; 72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (rc != Z_OK) 74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (flateData.avail_in == 0) { 76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (input != nullptr) 77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot size_t read = src->read(&inputBuffer, kBufferSize); 79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (read == 0) 80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.next_in = inputBuffer; 82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.avail_in = SkToUInt(read); 83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot rc = inflate(&flateData, Z_NO_FLUSH); 85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (rc == Z_OK) { 87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot rc = inflate(&flateData, Z_FINISH); 88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (flateData.avail_out < kBufferSize) { 89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) { 90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(reporter, "write failed"); 91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.next_out = outputBuffer; 94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot flateData.avail_out = kBufferSize; 95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot inflateEnd(&flateData); 99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (rc != Z_STREAM_END) { 100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(reporter, "Zlib: inflateEnd failed"); 101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return nullptr; 102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return decompressedDynamicMemoryWStream.detachAsStream(); 104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} // namespace 106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_TEST(SkPDF_DeflateWStream, r) { 108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkRandom random(123456); 109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (int i = 0; i < 50; ++i) { 110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t size = random.nextULessThan(10000); 111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkAutoTMalloc<uint8_t> buffer(size); 112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (uint32_t j = 0; j < size; ++j) { 113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot buffer[j] = random.nextU() & 0xff; 114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDynamicMemoryWStream dynamicMemoryWStream; 117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot { 118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDeflateWStream deflateWStream(&dynamicMemoryWStream); 119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t j = 0; 120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot while (j < size) { 121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t writeSize = 122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkTMin(size - j, random.nextRangeU(1, 400)); 123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!deflateWStream.write(&buffer[j], writeSize)) { 124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(r, "something went wrong."); 125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot j += writeSize; 128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(r, deflateWStream.bytesWritten() == size); 130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot std::unique_ptr<SkStreamAsset> compressed(dynamicMemoryWStream.detachAsStream()); 132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot std::unique_ptr<SkStreamAsset> decompressed(stream_inflate(r, compressed.get())); 133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (!decompressed) { 135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(r, "Decompression failed."); 136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot return; 137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (decompressed->getLength() != size) { 139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(r, "Decompression failed to get right size [%d]." 140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot " %u != %u", i, (unsigned)(decompressed->getLength()), 141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot (unsigned)size); 142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkString s = SkStringPrintf("/tmp/deftst_compressed_%d", i); 143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkFILEWStream o(s.c_str()); 144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot o.writeStream(compressed.get(), compressed->getLength()); 145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot compressed->rewind(); 146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot s = SkStringPrintf("/tmp/deftst_input_%d", i); 148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkFILEWStream o2(s.c_str()); 149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot o2.write(&buffer[0], size); 150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot continue; 152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint32_t minLength = SkTMin(size, 154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot (uint32_t)(decompressed->getLength())); 155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot for (uint32_t i = 0; i < minLength; ++i) { 156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot uint8_t c; 157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDEBUGCODE(size_t rb =)decompressed->read(&c, sizeof(uint8_t)); 158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkASSERT(sizeof(uint8_t) == rb); 159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot if (buffer[i] != c) { 160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot ERRORF(r, "Decompression failed at byte %u.", (unsigned)i); 161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot break; 162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot } 165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot SkDeflateWStream emptyDeflateWStream(nullptr); 166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot REPORTER_ASSERT(r, !emptyDeflateWStream.writeText("FOO")); 167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} 168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot 169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif 170