method.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /*
  2. * Copyright (c) Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under both the BSD-style license (found in the
  6. * LICENSE file in the root directory of this source tree) and the GPLv2 (found
  7. * in the COPYING file in the root directory of this source tree).
  8. * You may select, at your option, one of the above-listed licenses.
  9. */
  10. #include "method.h"
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #define ZSTD_STATIC_LINKING_ONLY
  14. #include <zstd.h>
  15. #define MIN(x, y) ((x) < (y) ? (x) : (y))
  16. static char const* g_zstdcli = NULL;
  17. void method_set_zstdcli(char const* zstdcli) {
  18. g_zstdcli = zstdcli;
  19. }
  20. /**
  21. * Macro to get a pointer of type, given ptr, which is a member variable with
  22. * the given name, member.
  23. *
  24. * method_state_t* base = ...;
  25. * buffer_state_t* state = container_of(base, buffer_state_t, base);
  26. */
  27. #define container_of(ptr, type, member) \
  28. ((type*)(ptr == NULL ? NULL : (char*)(ptr)-offsetof(type, member)))
  29. /** State to reuse the same buffers between compression calls. */
  30. typedef struct {
  31. method_state_t base;
  32. data_buffers_t inputs; /**< The input buffer for each file. */
  33. data_buffer_t dictionary; /**< The dictionary. */
  34. data_buffer_t compressed; /**< The compressed data buffer. */
  35. data_buffer_t decompressed; /**< The decompressed data buffer. */
  36. } buffer_state_t;
  37. static size_t buffers_max_size(data_buffers_t buffers) {
  38. size_t max = 0;
  39. for (size_t i = 0; i < buffers.size; ++i) {
  40. if (buffers.buffers[i].size > max)
  41. max = buffers.buffers[i].size;
  42. }
  43. return max;
  44. }
  45. static method_state_t* buffer_state_create(data_t const* data) {
  46. buffer_state_t* state = (buffer_state_t*)calloc(1, sizeof(buffer_state_t));
  47. if (state == NULL)
  48. return NULL;
  49. state->base.data = data;
  50. state->inputs = data_buffers_get(data);
  51. state->dictionary = data_buffer_get_dict(data);
  52. size_t const max_size = buffers_max_size(state->inputs);
  53. state->compressed = data_buffer_create(ZSTD_compressBound(max_size));
  54. state->decompressed = data_buffer_create(max_size);
  55. return &state->base;
  56. }
  57. static void buffer_state_destroy(method_state_t* base) {
  58. if (base == NULL)
  59. return;
  60. buffer_state_t* state = container_of(base, buffer_state_t, base);
  61. free(state);
  62. }
  63. static int buffer_state_bad(
  64. buffer_state_t const* state,
  65. config_t const* config) {
  66. if (state == NULL) {
  67. fprintf(stderr, "buffer_state_t is NULL\n");
  68. return 1;
  69. }
  70. if (state->inputs.size == 0 || state->compressed.data == NULL ||
  71. state->decompressed.data == NULL) {
  72. fprintf(stderr, "buffer state allocation failure\n");
  73. return 1;
  74. }
  75. if (config->use_dictionary && state->dictionary.data == NULL) {
  76. fprintf(stderr, "dictionary loading failed\n");
  77. return 1;
  78. }
  79. return 0;
  80. }
  81. static result_t simple_compress(method_state_t* base, config_t const* config) {
  82. buffer_state_t* state = container_of(base, buffer_state_t, base);
  83. if (buffer_state_bad(state, config))
  84. return result_error(result_error_system_error);
  85. /* Keep the tests short by skipping directories, since behavior shouldn't
  86. * change.
  87. */
  88. if (base->data->type != data_type_file)
  89. return result_error(result_error_skip);
  90. if (config->advanced_api_only)
  91. return result_error(result_error_skip);
  92. if (config->use_dictionary || config->no_pledged_src_size)
  93. return result_error(result_error_skip);
  94. /* If the config doesn't specify a level, skip. */
  95. int const level = config_get_level(config);
  96. if (level == CONFIG_NO_LEVEL)
  97. return result_error(result_error_skip);
  98. data_buffer_t const input = state->inputs.buffers[0];
  99. /* Compress, decompress, and check the result. */
  100. state->compressed.size = ZSTD_compress(
  101. state->compressed.data,
  102. state->compressed.capacity,
  103. input.data,
  104. input.size,
  105. level);
  106. if (ZSTD_isError(state->compressed.size))
  107. return result_error(result_error_compression_error);
  108. state->decompressed.size = ZSTD_decompress(
  109. state->decompressed.data,
  110. state->decompressed.capacity,
  111. state->compressed.data,
  112. state->compressed.size);
  113. if (ZSTD_isError(state->decompressed.size))
  114. return result_error(result_error_decompression_error);
  115. if (data_buffer_compare(input, state->decompressed))
  116. return result_error(result_error_round_trip_error);
  117. result_data_t data;
  118. data.total_size = state->compressed.size;
  119. return result_data(data);
  120. }
  121. static result_t compress_cctx_compress(
  122. method_state_t* base,
  123. config_t const* config) {
  124. buffer_state_t* state = container_of(base, buffer_state_t, base);
  125. if (buffer_state_bad(state, config))
  126. return result_error(result_error_system_error);
  127. if (config->no_pledged_src_size)
  128. return result_error(result_error_skip);
  129. if (base->data->type != data_type_dir)
  130. return result_error(result_error_skip);
  131. if (config->advanced_api_only)
  132. return result_error(result_error_skip);
  133. int const level = config_get_level(config);
  134. ZSTD_CCtx* cctx = ZSTD_createCCtx();
  135. ZSTD_DCtx* dctx = ZSTD_createDCtx();
  136. if (cctx == NULL || dctx == NULL) {
  137. fprintf(stderr, "context creation failed\n");
  138. return result_error(result_error_system_error);
  139. }
  140. result_t result;
  141. result_data_t data = {.total_size = 0};
  142. for (size_t i = 0; i < state->inputs.size; ++i) {
  143. data_buffer_t const input = state->inputs.buffers[i];
  144. ZSTD_parameters const params =
  145. config_get_zstd_params(config, input.size, state->dictionary.size);
  146. if (level == CONFIG_NO_LEVEL)
  147. state->compressed.size = ZSTD_compress_advanced(
  148. cctx,
  149. state->compressed.data,
  150. state->compressed.capacity,
  151. input.data,
  152. input.size,
  153. config->use_dictionary ? state->dictionary.data : NULL,
  154. config->use_dictionary ? state->dictionary.size : 0,
  155. params);
  156. else if (config->use_dictionary)
  157. state->compressed.size = ZSTD_compress_usingDict(
  158. cctx,
  159. state->compressed.data,
  160. state->compressed.capacity,
  161. input.data,
  162. input.size,
  163. state->dictionary.data,
  164. state->dictionary.size,
  165. level);
  166. else
  167. state->compressed.size = ZSTD_compressCCtx(
  168. cctx,
  169. state->compressed.data,
  170. state->compressed.capacity,
  171. input.data,
  172. input.size,
  173. level);
  174. if (ZSTD_isError(state->compressed.size)) {
  175. result = result_error(result_error_compression_error);
  176. goto out;
  177. }
  178. if (config->use_dictionary)
  179. state->decompressed.size = ZSTD_decompress_usingDict(
  180. dctx,
  181. state->decompressed.data,
  182. state->decompressed.capacity,
  183. state->compressed.data,
  184. state->compressed.size,
  185. state->dictionary.data,
  186. state->dictionary.size);
  187. else
  188. state->decompressed.size = ZSTD_decompressDCtx(
  189. dctx,
  190. state->decompressed.data,
  191. state->decompressed.capacity,
  192. state->compressed.data,
  193. state->compressed.size);
  194. if (ZSTD_isError(state->decompressed.size)) {
  195. result = result_error(result_error_decompression_error);
  196. goto out;
  197. }
  198. if (data_buffer_compare(input, state->decompressed)) {
  199. result = result_error(result_error_round_trip_error);
  200. goto out;
  201. }
  202. data.total_size += state->compressed.size;
  203. }
  204. result = result_data(data);
  205. out:
  206. ZSTD_freeCCtx(cctx);
  207. ZSTD_freeDCtx(dctx);
  208. return result;
  209. }
  210. /** Generic state creation function. */
  211. static method_state_t* method_state_create(data_t const* data) {
  212. method_state_t* state = (method_state_t*)malloc(sizeof(method_state_t));
  213. if (state == NULL)
  214. return NULL;
  215. state->data = data;
  216. return state;
  217. }
  218. static void method_state_destroy(method_state_t* state) {
  219. free(state);
  220. }
  221. static result_t cli_compress(method_state_t* state, config_t const* config) {
  222. if (config->cli_args == NULL)
  223. return result_error(result_error_skip);
  224. if (config->advanced_api_only)
  225. return result_error(result_error_skip);
  226. /* We don't support no pledged source size with directories. Too slow. */
  227. if (state->data->type == data_type_dir && config->no_pledged_src_size)
  228. return result_error(result_error_skip);
  229. if (g_zstdcli == NULL)
  230. return result_error(result_error_system_error);
  231. /* '<zstd>' -cqr <args> [-D '<dict>'] '<file/dir>' */
  232. char cmd[1024];
  233. size_t const cmd_size = snprintf(
  234. cmd,
  235. sizeof(cmd),
  236. "'%s' -cqr %s %s%s%s %s '%s'",
  237. g_zstdcli,
  238. config->cli_args,
  239. config->use_dictionary ? "-D '" : "",
  240. config->use_dictionary ? state->data->dict.path : "",
  241. config->use_dictionary ? "'" : "",
  242. config->no_pledged_src_size ? "<" : "",
  243. state->data->data.path);
  244. if (cmd_size >= sizeof(cmd)) {
  245. fprintf(stderr, "command too large: %s\n", cmd);
  246. return result_error(result_error_system_error);
  247. }
  248. FILE* zstd = popen(cmd, "r");
  249. if (zstd == NULL) {
  250. fprintf(stderr, "failed to popen command: %s\n", cmd);
  251. return result_error(result_error_system_error);
  252. }
  253. char out[4096];
  254. size_t total_size = 0;
  255. while (1) {
  256. size_t const size = fread(out, 1, sizeof(out), zstd);
  257. total_size += size;
  258. if (size != sizeof(out))
  259. break;
  260. }
  261. if (ferror(zstd) || pclose(zstd) != 0) {
  262. fprintf(stderr, "zstd failed with command: %s\n", cmd);
  263. return result_error(result_error_compression_error);
  264. }
  265. result_data_t const data = {.total_size = total_size};
  266. return result_data(data);
  267. }
  268. static int advanced_config(
  269. ZSTD_CCtx* cctx,
  270. buffer_state_t* state,
  271. config_t const* config) {
  272. ZSTD_CCtx_reset(cctx, ZSTD_reset_session_and_parameters);
  273. for (size_t p = 0; p < config->param_values.size; ++p) {
  274. param_value_t const pv = config->param_values.data[p];
  275. if (ZSTD_isError(ZSTD_CCtx_setParameter(cctx, pv.param, pv.value))) {
  276. return 1;
  277. }
  278. }
  279. if (config->use_dictionary) {
  280. if (ZSTD_isError(ZSTD_CCtx_loadDictionary(
  281. cctx, state->dictionary.data, state->dictionary.size))) {
  282. return 1;
  283. }
  284. }
  285. return 0;
  286. }
  287. static result_t advanced_one_pass_compress_output_adjustment(
  288. method_state_t* base,
  289. config_t const* config,
  290. size_t const subtract) {
  291. buffer_state_t* state = container_of(base, buffer_state_t, base);
  292. if (buffer_state_bad(state, config))
  293. return result_error(result_error_system_error);
  294. ZSTD_CCtx* cctx = ZSTD_createCCtx();
  295. result_t result;
  296. if (!cctx || advanced_config(cctx, state, config)) {
  297. result = result_error(result_error_compression_error);
  298. goto out;
  299. }
  300. result_data_t data = {.total_size = 0};
  301. for (size_t i = 0; i < state->inputs.size; ++i) {
  302. data_buffer_t const input = state->inputs.buffers[i];
  303. if (!config->no_pledged_src_size) {
  304. if (ZSTD_isError(ZSTD_CCtx_setPledgedSrcSize(cctx, input.size))) {
  305. result = result_error(result_error_compression_error);
  306. goto out;
  307. }
  308. }
  309. size_t const size = ZSTD_compress2(
  310. cctx,
  311. state->compressed.data,
  312. ZSTD_compressBound(input.size) - subtract,
  313. input.data,
  314. input.size);
  315. if (ZSTD_isError(size)) {
  316. result = result_error(result_error_compression_error);
  317. goto out;
  318. }
  319. data.total_size += size;
  320. }
  321. result = result_data(data);
  322. out:
  323. ZSTD_freeCCtx(cctx);
  324. return result;
  325. }
  326. static result_t advanced_one_pass_compress(
  327. method_state_t* base,
  328. config_t const* config) {
  329. return advanced_one_pass_compress_output_adjustment(base, config, 0);
  330. }
  331. static result_t advanced_one_pass_compress_small_output(
  332. method_state_t* base,
  333. config_t const* config) {
  334. return advanced_one_pass_compress_output_adjustment(base, config, 1);
  335. }
  336. static result_t advanced_streaming_compress(
  337. method_state_t* base,
  338. config_t const* config) {
  339. buffer_state_t* state = container_of(base, buffer_state_t, base);
  340. if (buffer_state_bad(state, config))
  341. return result_error(result_error_system_error);
  342. ZSTD_CCtx* cctx = ZSTD_createCCtx();
  343. result_t result;
  344. if (!cctx || advanced_config(cctx, state, config)) {
  345. result = result_error(result_error_compression_error);
  346. goto out;
  347. }
  348. result_data_t data = {.total_size = 0};
  349. for (size_t i = 0; i < state->inputs.size; ++i) {
  350. data_buffer_t input = state->inputs.buffers[i];
  351. if (!config->no_pledged_src_size) {
  352. if (ZSTD_isError(ZSTD_CCtx_setPledgedSrcSize(cctx, input.size))) {
  353. result = result_error(result_error_compression_error);
  354. goto out;
  355. }
  356. }
  357. while (input.size > 0) {
  358. ZSTD_inBuffer in = {input.data, MIN(input.size, 4096)};
  359. input.data += in.size;
  360. input.size -= in.size;
  361. ZSTD_EndDirective const op =
  362. input.size > 0 ? ZSTD_e_continue : ZSTD_e_end;
  363. size_t ret = 0;
  364. while (in.pos < in.size || (op == ZSTD_e_end && ret != 0)) {
  365. ZSTD_outBuffer out = {state->compressed.data,
  366. MIN(state->compressed.capacity, 1024)};
  367. ret = ZSTD_compressStream2(cctx, &out, &in, op);
  368. if (ZSTD_isError(ret)) {
  369. result = result_error(result_error_compression_error);
  370. goto out;
  371. }
  372. data.total_size += out.pos;
  373. }
  374. }
  375. }
  376. result = result_data(data);
  377. out:
  378. ZSTD_freeCCtx(cctx);
  379. return result;
  380. }
  381. static int init_cstream(
  382. buffer_state_t* state,
  383. ZSTD_CStream* zcs,
  384. config_t const* config,
  385. int const advanced,
  386. ZSTD_CDict** cdict)
  387. {
  388. size_t zret;
  389. if (advanced) {
  390. ZSTD_parameters const params = config_get_zstd_params(config, 0, 0);
  391. ZSTD_CDict* dict = NULL;
  392. if (cdict) {
  393. if (!config->use_dictionary)
  394. return 1;
  395. *cdict = ZSTD_createCDict_advanced(
  396. state->dictionary.data,
  397. state->dictionary.size,
  398. ZSTD_dlm_byRef,
  399. ZSTD_dct_auto,
  400. params.cParams,
  401. ZSTD_defaultCMem);
  402. if (!*cdict) {
  403. return 1;
  404. }
  405. zret = ZSTD_initCStream_usingCDict_advanced(
  406. zcs, *cdict, params.fParams, ZSTD_CONTENTSIZE_UNKNOWN);
  407. } else {
  408. zret = ZSTD_initCStream_advanced(
  409. zcs,
  410. config->use_dictionary ? state->dictionary.data : NULL,
  411. config->use_dictionary ? state->dictionary.size : 0,
  412. params,
  413. ZSTD_CONTENTSIZE_UNKNOWN);
  414. }
  415. } else {
  416. int const level = config_get_level(config);
  417. if (level == CONFIG_NO_LEVEL)
  418. return 1;
  419. if (cdict) {
  420. if (!config->use_dictionary)
  421. return 1;
  422. *cdict = ZSTD_createCDict(
  423. state->dictionary.data,
  424. state->dictionary.size,
  425. level);
  426. if (!*cdict) {
  427. return 1;
  428. }
  429. zret = ZSTD_initCStream_usingCDict(zcs, *cdict);
  430. } else if (config->use_dictionary) {
  431. zret = ZSTD_initCStream_usingDict(
  432. zcs,
  433. state->dictionary.data,
  434. state->dictionary.size,
  435. level);
  436. } else {
  437. zret = ZSTD_initCStream(zcs, level);
  438. }
  439. }
  440. if (ZSTD_isError(zret)) {
  441. return 1;
  442. }
  443. return 0;
  444. }
  445. static result_t old_streaming_compress_internal(
  446. method_state_t* base,
  447. config_t const* config,
  448. int const advanced,
  449. int const cdict) {
  450. buffer_state_t* state = container_of(base, buffer_state_t, base);
  451. if (buffer_state_bad(state, config))
  452. return result_error(result_error_system_error);
  453. ZSTD_CStream* zcs = ZSTD_createCStream();
  454. ZSTD_CDict* cd = NULL;
  455. result_t result;
  456. if (zcs == NULL) {
  457. result = result_error(result_error_compression_error);
  458. goto out;
  459. }
  460. if (!advanced && config_get_level(config) == CONFIG_NO_LEVEL) {
  461. result = result_error(result_error_skip);
  462. goto out;
  463. }
  464. if (cdict && !config->use_dictionary) {
  465. result = result_error(result_error_skip);
  466. goto out;
  467. }
  468. if (config->advanced_api_only) {
  469. result = result_error(result_error_skip);
  470. goto out;
  471. }
  472. if (init_cstream(state, zcs, config, advanced, cdict ? &cd : NULL)) {
  473. result = result_error(result_error_compression_error);
  474. goto out;
  475. }
  476. result_data_t data = {.total_size = 0};
  477. for (size_t i = 0; i < state->inputs.size; ++i) {
  478. data_buffer_t input = state->inputs.buffers[i];
  479. size_t zret = ZSTD_resetCStream(
  480. zcs,
  481. config->no_pledged_src_size ? ZSTD_CONTENTSIZE_UNKNOWN : input.size);
  482. if (ZSTD_isError(zret)) {
  483. result = result_error(result_error_compression_error);
  484. goto out;
  485. }
  486. while (input.size > 0) {
  487. ZSTD_inBuffer in = {input.data, MIN(input.size, 4096)};
  488. input.data += in.size;
  489. input.size -= in.size;
  490. ZSTD_EndDirective const op =
  491. input.size > 0 ? ZSTD_e_continue : ZSTD_e_end;
  492. zret = 0;
  493. while (in.pos < in.size || (op == ZSTD_e_end && zret != 0)) {
  494. ZSTD_outBuffer out = {state->compressed.data,
  495. MIN(state->compressed.capacity, 1024)};
  496. if (op == ZSTD_e_continue || in.pos < in.size)
  497. zret = ZSTD_compressStream(zcs, &out, &in);
  498. else
  499. zret = ZSTD_endStream(zcs, &out);
  500. if (ZSTD_isError(zret)) {
  501. result = result_error(result_error_compression_error);
  502. goto out;
  503. }
  504. data.total_size += out.pos;
  505. }
  506. }
  507. }
  508. result = result_data(data);
  509. out:
  510. ZSTD_freeCStream(zcs);
  511. ZSTD_freeCDict(cd);
  512. return result;
  513. }
  514. static result_t old_streaming_compress(
  515. method_state_t* base,
  516. config_t const* config)
  517. {
  518. return old_streaming_compress_internal(
  519. base, config, /* advanced */ 0, /* cdict */ 0);
  520. }
  521. static result_t old_streaming_compress_advanced(
  522. method_state_t* base,
  523. config_t const* config)
  524. {
  525. return old_streaming_compress_internal(
  526. base, config, /* advanced */ 1, /* cdict */ 0);
  527. }
  528. static result_t old_streaming_compress_cdict(
  529. method_state_t* base,
  530. config_t const* config)
  531. {
  532. return old_streaming_compress_internal(
  533. base, config, /* advanced */ 0, /* cdict */ 1);
  534. }
  535. static result_t old_streaming_compress_cdict_advanced(
  536. method_state_t* base,
  537. config_t const* config)
  538. {
  539. return old_streaming_compress_internal(
  540. base, config, /* advanced */ 1, /* cdict */ 1);
  541. }
  542. method_t const simple = {
  543. .name = "compress simple",
  544. .create = buffer_state_create,
  545. .compress = simple_compress,
  546. .destroy = buffer_state_destroy,
  547. };
  548. method_t const compress_cctx = {
  549. .name = "compress cctx",
  550. .create = buffer_state_create,
  551. .compress = compress_cctx_compress,
  552. .destroy = buffer_state_destroy,
  553. };
  554. method_t const advanced_one_pass = {
  555. .name = "advanced one pass",
  556. .create = buffer_state_create,
  557. .compress = advanced_one_pass_compress,
  558. .destroy = buffer_state_destroy,
  559. };
  560. method_t const advanced_one_pass_small_out = {
  561. .name = "advanced one pass small out",
  562. .create = buffer_state_create,
  563. .compress = advanced_one_pass_compress,
  564. .destroy = buffer_state_destroy,
  565. };
  566. method_t const advanced_streaming = {
  567. .name = "advanced streaming",
  568. .create = buffer_state_create,
  569. .compress = advanced_streaming_compress,
  570. .destroy = buffer_state_destroy,
  571. };
  572. method_t const old_streaming = {
  573. .name = "old streaming",
  574. .create = buffer_state_create,
  575. .compress = old_streaming_compress,
  576. .destroy = buffer_state_destroy,
  577. };
  578. method_t const old_streaming_advanced = {
  579. .name = "old streaming advanced",
  580. .create = buffer_state_create,
  581. .compress = old_streaming_compress_advanced,
  582. .destroy = buffer_state_destroy,
  583. };
  584. method_t const old_streaming_cdict = {
  585. .name = "old streaming cdict",
  586. .create = buffer_state_create,
  587. .compress = old_streaming_compress_cdict,
  588. .destroy = buffer_state_destroy,
  589. };
  590. method_t const old_streaming_advanced_cdict = {
  591. .name = "old streaming advanced cdict",
  592. .create = buffer_state_create,
  593. .compress = old_streaming_compress_cdict_advanced,
  594. .destroy = buffer_state_destroy,
  595. };
  596. method_t const cli = {
  597. .name = "zstdcli",
  598. .create = method_state_create,
  599. .compress = cli_compress,
  600. .destroy = method_state_destroy,
  601. };
  602. static method_t const* g_methods[] = {
  603. &simple,
  604. &compress_cctx,
  605. &cli,
  606. &advanced_one_pass,
  607. &advanced_one_pass_small_out,
  608. &advanced_streaming,
  609. &old_streaming,
  610. &old_streaming_advanced,
  611. &old_streaming_cdict,
  612. &old_streaming_advanced_cdict,
  613. NULL,
  614. };
  615. method_t const* const* methods = g_methods;