1*3117ece4Schristos /* 2*3117ece4Schristos * Copyright (c) Meta Platforms, Inc. and affiliates. 3*3117ece4Schristos * All rights reserved. 4*3117ece4Schristos * 5*3117ece4Schristos * This source code is licensed under both the BSD-style license (found in the 6*3117ece4Schristos * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*3117ece4Schristos * in the COPYING file in the root directory of this source tree). 8*3117ece4Schristos * You may select, at your option, one of the above-listed licenses. 9*3117ece4Schristos */ 10*3117ece4Schristos 11*3117ece4Schristos /* 12*3117ece4Schristos This program uses hard-coded data compressed with Zstd legacy versions 13*3117ece4Schristos and tests that the API decompresses them correctly 14*3117ece4Schristos */ 15*3117ece4Schristos 16*3117ece4Schristos /*=========================================== 17*3117ece4Schristos * Dependencies 18*3117ece4Schristos *==========================================*/ 19*3117ece4Schristos #include <stddef.h> /* size_t */ 20*3117ece4Schristos #include <stdlib.h> /* malloc, free */ 21*3117ece4Schristos #include <stdio.h> /* fprintf */ 22*3117ece4Schristos #include <string.h> /* strlen */ 23*3117ece4Schristos #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_decompressBound */ 24*3117ece4Schristos #include "zstd.h" 25*3117ece4Schristos #include "zstd_errors.h" 26*3117ece4Schristos 27*3117ece4Schristos /*=========================================== 28*3117ece4Schristos * Macros 29*3117ece4Schristos *==========================================*/ 30*3117ece4Schristos #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) 31*3117ece4Schristos 32*3117ece4Schristos /*=========================================== 33*3117ece4Schristos * Precompressed frames 34*3117ece4Schristos *==========================================*/ 35*3117ece4Schristos const char* const COMPRESSED; /* content is at end of file */ 36*3117ece4Schristos size_t const COMPRESSED_SIZE = 917; 37*3117ece4Schristos const char* const EXPECTED; /* content is at end of file */ 38*3117ece4Schristos 39*3117ece4Schristos 40*3117ece4Schristos static int testSimpleAPI(void) 41*3117ece4Schristos { 42*3117ece4Schristos size_t const size = strlen(EXPECTED); 43*3117ece4Schristos char* const output = malloc(size); 44*3117ece4Schristos 45*3117ece4Schristos if (!output) { 46*3117ece4Schristos DISPLAY("ERROR: Not enough memory!\n"); 47*3117ece4Schristos return 1; 48*3117ece4Schristos } 49*3117ece4Schristos 50*3117ece4Schristos { 51*3117ece4Schristos size_t const ret = ZSTD_decompress(output, size, COMPRESSED, COMPRESSED_SIZE); 52*3117ece4Schristos if (ZSTD_isError(ret)) { 53*3117ece4Schristos if (ret == ZSTD_error_prefix_unknown) { 54*3117ece4Schristos DISPLAY("ERROR: Invalid frame magic number, was this compiled " 55*3117ece4Schristos "without legacy support?\n"); 56*3117ece4Schristos } else { 57*3117ece4Schristos DISPLAY("ERROR: %s\n", ZSTD_getErrorName(ret)); 58*3117ece4Schristos } 59*3117ece4Schristos return 1; 60*3117ece4Schristos } 61*3117ece4Schristos if (ret != size) { 62*3117ece4Schristos DISPLAY("ERROR: Wrong decoded size\n"); 63*3117ece4Schristos } 64*3117ece4Schristos } 65*3117ece4Schristos if (memcmp(EXPECTED, output, size) != 0) { 66*3117ece4Schristos DISPLAY("ERROR: Wrong decoded output produced\n"); 67*3117ece4Schristos return 1; 68*3117ece4Schristos } 69*3117ece4Schristos 70*3117ece4Schristos free(output); 71*3117ece4Schristos DISPLAY("Simple API OK\n"); 72*3117ece4Schristos return 0; 73*3117ece4Schristos } 74*3117ece4Schristos 75*3117ece4Schristos 76*3117ece4Schristos static int testStreamingAPI(void) 77*3117ece4Schristos { 78*3117ece4Schristos int error_code = 0; 79*3117ece4Schristos size_t const outBuffSize = ZSTD_DStreamOutSize(); 80*3117ece4Schristos char* const outBuff = malloc(outBuffSize); 81*3117ece4Schristos ZSTD_DStream* const stream = ZSTD_createDStream(); 82*3117ece4Schristos ZSTD_inBuffer input = { COMPRESSED, COMPRESSED_SIZE, 0 }; 83*3117ece4Schristos size_t outputPos = 0; 84*3117ece4Schristos int needsInit = 1; 85*3117ece4Schristos 86*3117ece4Schristos if (outBuff == NULL) { 87*3117ece4Schristos DISPLAY("ERROR: Could not allocate memory\n"); 88*3117ece4Schristos return 1; 89*3117ece4Schristos } 90*3117ece4Schristos if (stream == NULL) { 91*3117ece4Schristos DISPLAY("ERROR: Could not create dstream\n"); 92*3117ece4Schristos free(outBuff); 93*3117ece4Schristos return 1; 94*3117ece4Schristos } 95*3117ece4Schristos 96*3117ece4Schristos while (1) { 97*3117ece4Schristos ZSTD_outBuffer output = {outBuff, outBuffSize, 0}; 98*3117ece4Schristos if (needsInit) { 99*3117ece4Schristos size_t const ret = ZSTD_initDStream(stream); 100*3117ece4Schristos if (ZSTD_isError(ret)) { 101*3117ece4Schristos DISPLAY("ERROR: ZSTD_initDStream: %s\n", ZSTD_getErrorName(ret)); 102*3117ece4Schristos error_code = 1; 103*3117ece4Schristos break; 104*3117ece4Schristos } } 105*3117ece4Schristos 106*3117ece4Schristos { size_t const ret = ZSTD_decompressStream(stream, &output, &input); 107*3117ece4Schristos if (ZSTD_isError(ret)) { 108*3117ece4Schristos DISPLAY("ERROR: ZSTD_decompressStream: %s\n", ZSTD_getErrorName(ret)); 109*3117ece4Schristos error_code = 1; 110*3117ece4Schristos break; 111*3117ece4Schristos } 112*3117ece4Schristos 113*3117ece4Schristos if (ret == 0) { 114*3117ece4Schristos needsInit = 1; 115*3117ece4Schristos } } 116*3117ece4Schristos 117*3117ece4Schristos if (memcmp(outBuff, EXPECTED + outputPos, output.pos) != 0) { 118*3117ece4Schristos DISPLAY("ERROR: Wrong decoded output produced\n"); 119*3117ece4Schristos error_code = 1; 120*3117ece4Schristos break; 121*3117ece4Schristos } 122*3117ece4Schristos outputPos += output.pos; 123*3117ece4Schristos if (input.pos == input.size && output.pos < output.size) { 124*3117ece4Schristos break; 125*3117ece4Schristos } 126*3117ece4Schristos } 127*3117ece4Schristos 128*3117ece4Schristos free(outBuff); 129*3117ece4Schristos ZSTD_freeDStream(stream); 130*3117ece4Schristos if (error_code == 0) DISPLAY("Streaming API OK\n"); 131*3117ece4Schristos return error_code; 132*3117ece4Schristos } 133*3117ece4Schristos 134*3117ece4Schristos static int testFrameDecoding(void) 135*3117ece4Schristos { 136*3117ece4Schristos if (strlen(EXPECTED) > ZSTD_decompressBound(COMPRESSED, COMPRESSED_SIZE)) { 137*3117ece4Schristos DISPLAY("ERROR: ZSTD_decompressBound: decompressed bound too small\n"); 138*3117ece4Schristos return 1; 139*3117ece4Schristos } 140*3117ece4Schristos { const char* ip = COMPRESSED; 141*3117ece4Schristos size_t remainingSize = COMPRESSED_SIZE; 142*3117ece4Schristos while (1) { 143*3117ece4Schristos size_t frameSize = ZSTD_findFrameCompressedSize(ip, remainingSize); 144*3117ece4Schristos if (ZSTD_isError(frameSize)) { 145*3117ece4Schristos DISPLAY("ERROR: ZSTD_findFrameCompressedSize: %s\n", ZSTD_getErrorName(frameSize)); 146*3117ece4Schristos return 1; 147*3117ece4Schristos } 148*3117ece4Schristos if (frameSize > remainingSize) { 149*3117ece4Schristos DISPLAY("ERROR: ZSTD_findFrameCompressedSize: expected frameSize to align with src buffer"); 150*3117ece4Schristos return 1; 151*3117ece4Schristos } 152*3117ece4Schristos ip += frameSize; 153*3117ece4Schristos remainingSize -= frameSize; 154*3117ece4Schristos if (remainingSize == 0) break; 155*3117ece4Schristos } 156*3117ece4Schristos } 157*3117ece4Schristos DISPLAY("Frame Decoding OK\n"); 158*3117ece4Schristos return 0; 159*3117ece4Schristos } 160*3117ece4Schristos 161*3117ece4Schristos int main(void) 162*3117ece4Schristos { 163*3117ece4Schristos { int const ret = testSimpleAPI(); 164*3117ece4Schristos if (ret) return ret; } 165*3117ece4Schristos { int const ret = testStreamingAPI(); 166*3117ece4Schristos if (ret) return ret; } 167*3117ece4Schristos { int const ret = testFrameDecoding(); 168*3117ece4Schristos if (ret) return ret; } 169*3117ece4Schristos 170*3117ece4Schristos DISPLAY("OK\n"); 171*3117ece4Schristos return 0; 172*3117ece4Schristos } 173*3117ece4Schristos 174*3117ece4Schristos /* Consists of the "EXPECTED" string compressed with default settings on 175*3117ece4Schristos - v0.4.3 176*3117ece4Schristos - v0.5.0 177*3117ece4Schristos - v0.6.0 178*3117ece4Schristos - v0.7.0 179*3117ece4Schristos - v0.8.0 180*3117ece4Schristos */ 181*3117ece4Schristos const char* const COMPRESSED = 182*3117ece4Schristos "\x24\xB5\x2F\xFD\x00\x00\x00\xBB\xB0\x02\xC0\x10\x00\x1E\xB0\x01" 183*3117ece4Schristos "\x02\x00\x00\x80\x00\xE8\x92\x34\x12\x97\xC8\xDF\xE9\xF3\xEF\x53" 184*3117ece4Schristos "\xEA\x1D\x27\x4F\x0C\x44\x90\x0C\x8D\xF1\xB4\x89\x17\x00\x18\x00" 185*3117ece4Schristos "\x18\x00\x3F\xE6\xE2\xE3\x74\xD6\xEC\xC9\x4A\xE0\x71\x71\x42\x3E" 186*3117ece4Schristos "\x64\x4F\x6A\x45\x4E\x78\xEC\x49\x03\x3F\xC6\x80\xAB\x8F\x75\x5E" 187*3117ece4Schristos "\x6F\x2E\x3E\x7E\xC6\xDC\x45\x69\x6C\xC5\xFD\xC7\x40\xB8\x84\x8A" 188*3117ece4Schristos "\x01\xEB\xA8\xD1\x40\x39\x90\x4C\x64\xF8\xEB\x53\xE6\x18\x0B\x67" 189*3117ece4Schristos "\x12\xAD\xB8\x99\xB3\x5A\x6F\x8A\x19\x03\x01\x50\x67\x56\xF5\x9F" 190*3117ece4Schristos "\x35\x84\x60\xA0\x60\x91\xC9\x0A\xDC\xAB\xAB\xE0\xE2\x81\xFA\xCF" 191*3117ece4Schristos "\xC6\xBA\x01\x0E\x00\x54\x00\x00\x19\x00\x00\x54\x14\x00\x24\x24" 192*3117ece4Schristos "\x04\xFE\x04\x84\x4E\x41\x00\x27\xE2\x02\xC4\xB1\x00\xD2\x51\x00" 193*3117ece4Schristos "\x79\x58\x41\x28\x00\xE0\x0C\x01\x68\x65\x00\x04\x13\x0C\xDA\x0C" 194*3117ece4Schristos "\x80\x22\x06\xC0\x00\x00\x25\xB5\x2F\xFD\x00\x00\x00\xAD\x12\xB0" 195*3117ece4Schristos "\x7D\x1E\xB0\x01\x02\x00\x00\x80\x00\xE8\x92\x34\x12\x97\xC8\xDF" 196*3117ece4Schristos "\xE9\xF3\xEF\x53\xEA\x1D\x27\x4F\x0C\x44\x90\x0C\x8D\xF1\xB4\x89" 197*3117ece4Schristos "\x03\x01\x50\x67\x56\xF5\x9F\x35\x84\x60\xA0\x60\x91\xC9\x0A\xDC" 198*3117ece4Schristos "\xAB\xAB\xE0\xE2\x81\xFA\xCF\xC6\xBA\xEB\xA8\xD1\x40\x39\x90\x4C" 199*3117ece4Schristos "\x64\xF8\xEB\x53\xE6\x18\x0B\x67\x12\xAD\xB8\x99\xB3\x5A\x6F\x8A" 200*3117ece4Schristos "\xF9\x63\x0C\xB8\xFA\x58\xE7\xF5\xE6\xE2\xE3\x67\xCC\x5D\x94\xC6" 201*3117ece4Schristos "\x56\xDC\x7F\x0C\x84\x4B\xA8\xF8\x63\x2E\x3E\x4E\x67\xCD\x9E\xAC" 202*3117ece4Schristos "\x04\x1E\x17\x27\xE4\x43\xF6\xA4\x56\xE4\x84\xC7\x9E\x34\x0E\x00" 203*3117ece4Schristos "\x00\x32\x40\x80\xA8\x00\x01\x49\x81\xE0\x3C\x01\x29\x1D\x00\x87" 204*3117ece4Schristos "\xCE\x80\x75\x08\x80\x72\x24\x00\x7B\x52\x00\x94\x00\x20\xCC\x01" 205*3117ece4Schristos "\x86\xD2\x00\x81\x09\x83\xC1\x34\xA0\x88\x01\xC0\x00\x00\x26\xB5" 206*3117ece4Schristos "\x2F\xFD\x42\xEF\x00\x00\xA6\x12\xB0\x7D\x1E\xB0\x01\x02\x00\x00" 207*3117ece4Schristos "\x54\xA0\xBA\x24\x8D\xC4\x25\xF2\x77\xFA\xFC\xFB\x94\x7A\xC7\xC9" 208*3117ece4Schristos "\x13\x03\x11\x24\x43\x63\x3C\x6D\x22\x03\x01\x50\x67\x56\xF5\x9F" 209*3117ece4Schristos "\x35\x84\x60\xA0\x60\x91\xC9\x0A\xDC\xAB\xAB\xE0\xE2\x81\xFA\xCF" 210*3117ece4Schristos "\xC6\xBA\xEB\xA8\xD1\x40\x39\x90\x4C\x64\xF8\xEB\x53\xE6\x18\x0B" 211*3117ece4Schristos "\x67\x12\xAD\xB8\x99\xB3\x5A\x6F\x8A\xF9\x63\x0C\xB8\xFA\x58\xE7" 212*3117ece4Schristos "\xF5\xE6\xE2\xE3\x67\xCC\x5D\x94\xC6\x56\xDC\x7F\x0C\x84\x4B\xA8" 213*3117ece4Schristos "\xF8\x63\x2E\x3E\x4E\x67\xCD\x9E\xAC\x04\x1E\x17\x27\xE4\x43\xF6" 214*3117ece4Schristos "\xA4\x56\xE4\x84\xC7\x9E\x34\x0E\x00\x35\x0B\x71\xB5\xC0\x2A\x5C" 215*3117ece4Schristos "\x26\x94\x22\x20\x8B\x4C\x8D\x13\x47\x58\x67\x15\x6C\xF1\x1C\x4B" 216*3117ece4Schristos "\x54\x10\x9D\x31\x50\x85\x4B\x54\x0E\x01\x4B\x3D\x01\xC0\x00\x00" 217*3117ece4Schristos "\x27\xB5\x2F\xFD\x20\xEF\x00\x00\xA6\x12\xE4\x84\x1F\xB0\x01\x10" 218*3117ece4Schristos "\x00\x00\x00\x35\x59\xA6\xE7\xA1\xEF\x7C\xFC\xBD\x3F\xFF\x9F\xEF" 219*3117ece4Schristos "\xEE\xEF\x61\xC3\xAA\x31\x1D\x34\x38\x22\x22\x04\x44\x21\x80\x32" 220*3117ece4Schristos "\xAD\x28\xF3\xD6\x28\x0C\x0A\x0E\xD6\x5C\xAC\x19\x8D\x20\x5F\x45" 221*3117ece4Schristos "\x02\x2E\x17\x50\x66\x6D\xAC\x8B\x9C\x6E\x07\x73\x46\xBB\x44\x14" 222*3117ece4Schristos "\xE7\x98\xC3\xB9\x17\x32\x6E\x33\x7C\x0E\x21\xB1\xDB\xCB\x89\x51" 223*3117ece4Schristos "\x23\x34\xAB\x9D\xBC\x6D\x20\xF5\x03\xA9\x91\x4C\x2E\x1F\x59\xDB" 224*3117ece4Schristos "\xD9\x35\x67\x4B\x0C\x95\x79\x10\x00\x85\xA6\x96\x95\x2E\xDF\x78" 225*3117ece4Schristos "\x7B\x4A\x5C\x09\x76\x97\xD1\x5C\x96\x12\x75\x35\xA3\x55\x4A\xD4" 226*3117ece4Schristos "\x0B\x00\x35\x0B\x71\xB5\xC0\x2A\x5C\xE6\x08\x45\xF1\x39\x43\xF1" 227*3117ece4Schristos "\x1C\x4B\x54\x10\x9D\x31\x50\x85\x4B\x54\x0E\x01\x4B\x3D\x01\xC0" 228*3117ece4Schristos "\x00\x00\x28\xB5\x2F\xFD\x24\xEF\x35\x05\x00\x92\x0B\x21\x1F\xB0" 229*3117ece4Schristos "\x01\x10\x00\x00\x00\x35\x59\xA6\xE7\xA1\xEF\x7C\xFC\xBD\x3F\xFF" 230*3117ece4Schristos "\x9F\xEF\xEE\xEF\x61\xC3\xAA\x31\x1D\x34\x38\x22\x22\x04\x44\x21" 231*3117ece4Schristos "\x80\x32\xAD\x28\xF3\xD6\x28\x0C\x0A\x0E\xD6\x5C\xAC\x19\x8D\x20" 232*3117ece4Schristos "\x5F\x45\x02\x2E\x17\x50\x66\x6D\xAC\x8B\x9C\x6E\x07\x73\x46\xBB" 233*3117ece4Schristos "\x44\x14\xE7\x98\xC3\xB9\x17\x32\x6E\x33\x7C\x0E\x21\xB1\xDB\xCB" 234*3117ece4Schristos "\x89\x51\x23\x34\xAB\x9D\xBC\x6D\x20\xF5\x03\xA9\x91\x4C\x2E\x1F" 235*3117ece4Schristos "\x59\xDB\xD9\x35\x67\x4B\x0C\x95\x79\x10\x00\x85\xA6\x96\x95\x2E" 236*3117ece4Schristos "\xDF\x78\x7B\x4A\x5C\x09\x76\x97\xD1\x5C\x96\x12\x75\x35\xA3\x55" 237*3117ece4Schristos "\x4A\xD4\x0B\x00\x35\x0B\x71\xB5\xC0\x2A\x5C\xE6\x08\x45\xF1\x39" 238*3117ece4Schristos "\x43\xF1\x1C\x4B\x54\x10\x9D\x31\x50\x85\x4B\x54\x0E\x01\x4B\x3D" 239*3117ece4Schristos "\x01\xD2\x2F\x21\x80"; 240*3117ece4Schristos 241*3117ece4Schristos const char* const EXPECTED = 242*3117ece4Schristos "snowden is snowed in / he's now then in his snow den / when does the snow end?\n" 243*3117ece4Schristos "goodbye little dog / you dug some holes in your day / they'll be hard to fill.\n" 244*3117ece4Schristos "when life shuts a door, / just open it. it’s a door. / that is how doors work.\n" 245*3117ece4Schristos 246*3117ece4Schristos "snowden is snowed in / he's now then in his snow den / when does the snow end?\n" 247*3117ece4Schristos "goodbye little dog / you dug some holes in your day / they'll be hard to fill.\n" 248*3117ece4Schristos "when life shuts a door, / just open it. it’s a door. / that is how doors work.\n" 249*3117ece4Schristos 250*3117ece4Schristos "snowden is snowed in / he's now then in his snow den / when does the snow end?\n" 251*3117ece4Schristos "goodbye little dog / you dug some holes in your day / they'll be hard to fill.\n" 252*3117ece4Schristos "when life shuts a door, / just open it. it’s a door. / that is how doors work.\n" 253*3117ece4Schristos 254*3117ece4Schristos "snowden is snowed in / he's now then in his snow den / when does the snow end?\n" 255*3117ece4Schristos "goodbye little dog / you dug some holes in your day / they'll be hard to fill.\n" 256*3117ece4Schristos "when life shuts a door, / just open it. it’s a door. / that is how doors work.\n" 257*3117ece4Schristos 258*3117ece4Schristos "snowden is snowed in / he's now then in his snow den / when does the snow end?\n" 259*3117ece4Schristos "goodbye little dog / you dug some holes in your day / they'll be hard to fill.\n" 260*3117ece4Schristos "when life shuts a door, / just open it. it’s a door. / that is how doors work.\n"; 261