tools/squashfs4: update to version 4.2 (adds support for xz compression)
[openwrt/staging/lynxis.git] / tools / squashfs4 / patches / 160-expose_lzma_xz_options.patch
diff --git a/tools/squashfs4/patches/160-expose_lzma_xz_options.patch b/tools/squashfs4/patches/160-expose_lzma_xz_options.patch
new file mode 100644 (file)
index 0000000..b5fb80d
--- /dev/null
@@ -0,0 +1,926 @@
+--- /dev/null
++++ b/squashfs-tools/lzma_xz_options.h
+@@ -0,0 +1,112 @@
++#ifndef LZMA_XZ_OPTIONS_H
++#define LZMA_XZ_OPTIONS_H
++/*
++ * Copyright (c) 2011
++ * Jonas Gorski <jonas.gorski@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * lzma_options.h
++ */
++
++#include <stdint.h>
++
++#ifndef linux
++#define __BYTE_ORDER BYTE_ORDER
++#define __BIG_ENDIAN BIG_ENDIAN
++#define __LITTLE_ENDIAN LITTLE_ENDIAN
++#else
++#include <endian.h>
++#endif
++
++
++
++struct lzma_opts {
++      uint32_t flags;
++#define LZMA_OPT_FLT_MASK     0xffff
++#define LZMA_OPT_PRE_OFF      16
++#define LZMA_OPT_PRE_MASK     (0xf << LZMA_OPT_PRE_OFF)
++#define LZMA_OPT_EXTREME      20      
++      uint16_t bit_opts;
++#define LZMA_OPT_LC_OFF               0
++#define LZMA_OPT_LC_MASK      (0x7 << LZMA_OPT_LC_OFF)
++#define LZMA_OPT_LP_OFF               3
++#define LZMA_OPT_LP_MASK      (0x7 << LZMA_OPT_LP_OFF)
++#define LZMA_OPT_PB_OFF               6
++#define LZMA_OPT_PB_MASK      (0x7 << LZMA_OPT_PB_OFF)
++      uint16_t fb;
++      uint32_t dict_size;
++};
++
++#if __BYTE_ORDER == __BIG_ENDIAN
++extern unsigned int inswap_le32(unsigned int);
++
++#define SQUASHFS_INSWAP_LZMA_COMP_OPTS(s) { \
++      (s)->flags = inswap_le32((s)->flags); \
++      (s)->bit_opts = inswap_le16((s)->bit_opts); \
++      (s)->fb = inswap_le16((s)->fb); \
++      (s)->dict_size = inswap_le32((s)->dict_size); \
++}
++#else
++#define SQUASHFS_INSWAP_LZMA_COMP_OPTS(s)
++#endif
++
++#define MEMLIMIT (32 * 1024 * 1024)
++
++#define LZMA_OPT_LC_MIN               0
++#define LZMA_OPT_LC_MAX               4
++#define LZMA_OPT_LC_DEFAULT   3
++
++#define LZMA_OPT_LP_MIN               0
++#define LZMA_OPT_LP_MAX               4
++#define LZMA_OPT_LP_DEFAULT   0
++
++#define LZMA_OPT_PB_MIN               0
++#define LZMA_OPT_PB_MAX               4
++#define LZMA_OPT_PB_DEFAULT   2
++
++#define LZMA_OPT_FB_MIN               5
++#define LZMA_OPT_FB_MAX               273
++#define LZMA_OPT_FB_DEFAULT   64
++
++enum {
++      LZMA_OPT_LZMA = 1,
++      LZMA_OPT_XZ
++};
++
++struct lzma_xz_options {
++      int preset;
++      int extreme;
++      int lc;
++      int lp;
++      int pb;
++      int fb;
++      int dict_size;
++      int flags;
++};
++
++struct lzma_xz_options *lzma_xz_get_options(void);
++
++int lzma_xz_options(char *argv[], int argc, int lzmaver);
++
++int lzma_xz_options_post(int block_size, int lzmaver);
++
++void *lzma_xz_dump_options(int block_size, int *size, int flags);
++
++int lzma_xz_extract_options(int block_size, void *buffer, int size, int lzmaver);
++
++void lzma_xz_usage(int lzmaver);
++
++#endif
+--- /dev/null
++++ b/squashfs-tools/lzma_xz_options.c
+@@ -0,0 +1,365 @@
++/*
++ * Copyright (c) 2011
++ * Jonas Gorski <jonas.gorski@gmail.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2,
++ * or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * lzma_options.c
++ * 
++ * Common options for LZMA1 and 2 compressors. Based on xz_wrapper.c
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++
++#include <lzma.h>
++
++#include "lzma_xz_options.h"
++
++static const char const *lzmaver_str[] = { "", "lzma", "xz" };
++
++static struct lzma_xz_options options = {
++      .flags          = 0,
++      .preset         = 6,
++      .extreme        = 0,
++      .lc             = LZMA_OPT_LC_DEFAULT,
++      .lp             = LZMA_OPT_LP_DEFAULT,
++      .pb             = LZMA_OPT_PB_DEFAULT,
++      .fb             = LZMA_OPT_FB_DEFAULT,
++      .dict_size      = 0,
++};
++
++static float lzma_dict_percent = 0;
++
++struct lzma_xz_options *lzma_xz_get_options(void)
++{
++      return &options;
++}
++
++
++int lzma_xz_options(char *argv[], int argc, int lzmaver)
++{
++      const char *comp_name = lzmaver_str[lzmaver];
++      
++      if(strcmp(argv[0], "-Xpreset") == 0) {
++              int preset;
++              
++              if(argc < 2) {
++                      fprintf(stderr, "%s: -Xpreset missing preset\n", comp_name);
++                      goto failed;
++              }
++              
++              preset = atoi(argv[1]);
++              
++              if (preset < 0 || preset > 9) {
++                      fprintf(stderr, "%s: -Xpreset invalid value\n", comp_name);
++                      goto failed;
++              }
++              options.preset = preset;
++              return 1;
++      } else if(strcmp(argv[0], "-Xe") == 0) {
++              options.extreme = 1;
++              return 0;
++      } else if(strcmp(argv[0], "-Xlc") == 0) {
++              int lc;
++              
++              if(argc < 2) {
++                      fprintf(stderr, "%s: -Xlc missing lc\n", comp_name);
++                      goto failed;
++              }
++              
++              lc = atoi(argv[1]);
++              
++              if (lc < LZMA_OPT_LC_MIN || lc > LZMA_OPT_LC_MAX) {
++                      fprintf(stderr, "%s: -Xlc invalid value\n", comp_name);
++                      goto failed;
++              }
++              options.lc = lc;
++              return 1;
++      } else if(strcmp(argv[0], "-Xlp") == 0) {
++              int lp;
++              
++              if(argc < 2) {
++                      fprintf(stderr, "%s: -Xlp missing lp\n", comp_name);
++                      goto failed;
++              }
++              
++              lp = atoi(argv[1]);
++              
++              if (lp < LZMA_OPT_LP_MIN || lp > LZMA_OPT_LP_MAX) {
++                      fprintf(stderr, "%s: -Xlp invalid value\n", comp_name);
++                      goto failed;
++              }
++              options.lp = lp;
++              return 1;
++      } else if(strcmp(argv[0], "-Xpb") == 0) {
++              int pb;
++              
++              if(argc < 2) {
++                      fprintf(stderr, "%s: -Xpb missing pb\n", comp_name);
++                      goto failed;
++              }
++              
++              pb = atoi(argv[1]);
++              
++              if (pb < LZMA_OPT_PB_MIN || pb > LZMA_OPT_PB_MAX) {
++                      fprintf(stderr, "%s: -Xbp invalid value\n", comp_name);
++                      goto failed;
++              }
++              options.pb = pb;
++              return 1;       
++      } else if(strcmp(argv[0], "-Xfb") == 0) {
++              int fb;
++              
++              if(argc < 2) {
++                      fprintf(stderr, "%s: -Xfb missing fb\n", comp_name);
++                      goto failed;
++              }
++              
++              fb = atoi(argv[1]);
++              
++              if (fb < LZMA_OPT_FB_MIN || fb > LZMA_OPT_FB_MAX) {
++                      fprintf(stderr, "%s: -Xfb invalid value\n", comp_name);
++                      goto failed;
++              }
++              options.fb = fb;
++              return 1;
++      } else if(strcmp(argv[0], "-Xdict-size") == 0) {
++              char *b;
++              float size;
++
++              if(argc < 2) {
++                      fprintf(stderr, "%s: -Xdict-size missing dict-size\n", comp_name);
++                      goto failed;
++              }
++
++              size = strtof(argv[1], &b);
++              if(*b == '%') {
++                      if(size <= 0 || size > 100) {
++                              fprintf(stderr, "%s: -Xdict-size percentage "
++                                      "should be 0 < dict-size <= 100\n", comp_name);
++                              goto failed;
++                      }
++
++                      lzma_dict_percent = size;
++                      options.dict_size = 0;
++              } else {
++                      if((float) ((int) size) != size) {
++                              fprintf(stderr, "%s: -Xdict-size can't be "
++                                      "fractional unless a percentage of the"
++                                      " block size\n", comp_name);
++                              goto failed;
++                      }
++
++                      lzma_dict_percent = 0;
++                      options.dict_size = (int) size;
++
++                      if(*b == 'k' || *b == 'K')
++                              options.dict_size *= 1024;
++                      else if(*b == 'm' || *b == 'M')
++                              options.dict_size *= 1024 * 1024;
++                      else if(*b != '\0') {
++                              fprintf(stderr, "%s: -Xdict-size invalid "
++                                      "dict-size\n", comp_name);
++                              goto failed;
++                      }
++              }
++
++              return 1;
++      }
++      
++      return -1;
++      
++failed:
++      return -2;
++
++}
++
++int lzma_xz_options_post(int block_size, int lzmaver)
++{
++      const char *comp_name = lzmaver_str[lzmaver];
++      /*
++       * if -Xdict-size has been specified use this to compute the datablock
++       * dictionary size
++       */
++      if(options.dict_size || lzma_dict_percent) {
++              int dict_size_min = (lzmaver == 1 ? 4096 : 8192);
++              int n;
++
++              if(options.dict_size) {
++                      if(options.dict_size > block_size) {
++                              fprintf(stderr, "%s: -Xdict-size is larger than"
++                              " block_size\n", comp_name);
++                              goto failed;
++                      }
++              } else
++                      options.dict_size = block_size * lzma_dict_percent / 100;
++
++              if(options.dict_size < dict_size_min) {
++                      fprintf(stderr, "%s: -Xdict-size should be %i bytes "
++                              "or larger\n", comp_name, dict_size_min);
++                      goto failed;
++              }
++
++              /*
++               * dictionary_size must be storable in xz header as either
++               * 2^n or as  2^n+2^(n+1)
++              */
++              n = ffs(options.dict_size) - 1;
++              if(options.dict_size != (1 << n) &&
++                              options.dict_size != ((1 << n) + (1 << (n + 1)))) {
++                      fprintf(stderr, "%s: -Xdict-size is an unsupported "
++                              "value, dict-size must be storable in %s "
++                              "header\n", comp_name, comp_name);
++                      fprintf(stderr, "as either 2^n or as 2^n+2^(n+1).  "
++                              "Example dict-sizes are 75%%, 50%%, 37.5%%, "
++                              "25%%,\n");
++                      fprintf(stderr, "or 32K, 16K, 8K etc.\n");
++                      goto failed;
++              }
++
++      } else
++              /* No -Xdict-size specified, use defaults */
++              options.dict_size = block_size;
++
++      return 0;
++
++failed:
++      return -1;
++}
++
++static struct lzma_opts lzma_comp_opts;
++
++void *lzma_xz_dump_options(int block_size, int *size, int flags)
++{
++      /* No need to store default options */
++      if (options.preset == 6 &&
++                      options.extreme == 0 &&
++                      options.lc == LZMA_OPT_LC_DEFAULT &&
++                      options.lp == LZMA_OPT_LC_DEFAULT &&
++                      options.pb == LZMA_OPT_PB_DEFAULT &&
++                      options.fb == 0 &&
++                      options.dict_size == block_size &&
++                      flags == 0)
++              return NULL;
++      
++      *size = sizeof(struct lzma_opts);
++
++      lzma_comp_opts.flags |= flags;
++      
++      if (options.extreme)
++              lzma_comp_opts.flags |= LZMA_OPT_EXTREME;
++      
++      lzma_comp_opts.flags |= ((options.preset << LZMA_OPT_PRE_OFF) & LZMA_OPT_PRE_MASK);
++      
++      lzma_comp_opts.bit_opts = 
++                      ((options.lc << LZMA_OPT_LC_OFF) & LZMA_OPT_LC_MASK) |
++                      ((options.lp << LZMA_OPT_LP_OFF) & LZMA_OPT_LP_MASK) |
++                      ((options.pb << LZMA_OPT_PB_OFF) & LZMA_OPT_PB_MASK);
++      lzma_comp_opts.fb = options.fb;
++      lzma_comp_opts.dict_size = options.dict_size;
++      
++      SQUASHFS_INSWAP_LZMA_COMP_OPTS(&lzma_comp_opts);
++      
++      return &lzma_comp_opts;
++}
++
++int lzma_xz_extract_options(int block_size, void *buffer, int size, int lzmaver)
++{
++      if (size == 0) {
++              /* default options */
++              options.preset = 6;
++              options.extreme = 0;
++              options.lc = LZMA_OPT_LC_DEFAULT;
++              options.lp = LZMA_OPT_LC_DEFAULT;
++              options.pb = LZMA_OPT_PB_DEFAULT;
++              options.fb = LZMA_OPT_FB_DEFAULT;
++              options.dict_size = block_size;
++              options.flags = 0;
++      } else {
++              struct lzma_opts *comp_opts = buffer;
++              int n;
++              
++              if (size != sizeof(struct lzma_opts))
++                      goto failed;
++              
++              SQUASHFS_INSWAP_LZMA_COMP_OPTS(&comp_opts);
++              
++              options.flags = comp_opts->flags & LZMA_OPT_FLT_MASK;
++              options.preset  = (comp_opts->flags & LZMA_OPT_PRE_MASK) >> LZMA_OPT_PRE_OFF;
++              options.extreme = !!(comp_opts->flags & LZMA_OPT_EXTREME);
++
++              options.lc = (comp_opts->bit_opts & LZMA_OPT_LC_MASK) >> LZMA_OPT_LC_OFF;
++              options.lp = (comp_opts->bit_opts & LZMA_OPT_LP_MASK) >> LZMA_OPT_LP_OFF;
++              options.pb = (comp_opts->bit_opts & LZMA_OPT_PB_MASK) >> LZMA_OPT_PB_OFF;
++              options.fb = comp_opts->fb;
++              options.dict_size = comp_opts->dict_size;
++              
++              /* check that the LZMA bit options are in range */
++              if (options.lc < LZMA_OPT_LC_MIN || options.lc > LZMA_OPT_LC_MAX ||
++                      options.lp < LZMA_OPT_LP_MIN || options.lp > LZMA_OPT_LP_MAX ||
++                      options.pb < LZMA_OPT_PB_MIN || options.pb > LZMA_OPT_PB_MAX ||
++                      options.fb < LZMA_OPT_FB_MIN || options.fb > LZMA_OPT_FB_MAX)
++                      goto failed;
++
++              /*
++               * check that the dictionary size seems correct - the dictionary
++               * size should 2^n or 2^n+2^(n+1)
++               */
++              n = ffs(options.dict_size) - 1;
++              if(options.dict_size != (1 << n) &&
++                              options.dict_size != ((1 << n) + (1 << (n + 1))))
++                      goto failed;
++              
++      }
++      
++      return 0;
++
++failed:
++      fprintf(stderr, "%s: error reading stored compressor options from "
++              "filesystem!\n", lzmaver_str[lzmaver]);
++      return -1;      
++}
++
++void lzma_xz_usage(int lzmaver)
++{
++      fprintf(stderr, "\t  -Xpreset <preset>\n");
++      fprintf(stderr, "\t\tcompression preset (0-9, default 6)\n");
++      fprintf(stderr, "\t  -Xe\n");
++      fprintf(stderr, "\t\tTry to improve compression ratio by using more ");
++      fprintf(stderr, "CPU time.\n");
++      fprintf(stderr, "\t  -Xlc <lc>\n");
++      fprintf(stderr, "\t\tNumber of literal context bits (0-4, default 3)\n");
++      fprintf(stderr, "\t  -Xlp <lp>\n");
++      fprintf(stderr, "\t\tNumber of literal position bits (0-4, default 0)\n");
++      fprintf(stderr, "\t  -Xpb <pb>\n");
++      fprintf(stderr, "\t\tNumber of position bits (0-4, default 2)\n");
++      fprintf(stderr, "\t  -Xnice <nice>\n");
++      fprintf(stderr, "\t\tNice length of a match (5-273, default 64)\n");
++      fprintf(stderr, "\t  -Xdict-size <dict-size>\n");
++      fprintf(stderr, "\t\tUse <dict-size> as the %s dictionary size.  The",
++                      lzmaver == LZMA_OPT_LZMA ? "LZMA" : "XZ");
++      fprintf(stderr, " dictionary size\n\t\tcan be specified as a");
++      fprintf(stderr, " percentage of the block size, or as an\n\t\t");
++      fprintf(stderr, "absolute value.  The dictionary size must be less");
++      fprintf(stderr, " than or equal\n\t\tto the block size and %d bytes", 
++                      lzmaver == LZMA_OPT_LZMA ? 4096 : 8192);
++      fprintf(stderr, " or larger.  It must also be\n\t\tstorable in the lzma");
++      fprintf(stderr, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
++      fprintf(stderr, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
++      fprintf(stderr, " 32K, 16K, 8K\n\t\tetc.\n");
++      
++}
+--- a/squashfs-tools/lzma_xz_wrapper.c
++++ b/squashfs-tools/lzma_xz_wrapper.c
+@@ -27,6 +27,7 @@
+ #include "squashfs_fs.h"
+ #include "compressor.h"
++#include "lzma_xz_options.h"
+ #define LZMA_PROPS_SIZE 5
+ #define LZMA_UNCOMP_SIZE 8
+@@ -38,13 +39,27 @@
+ static int lzma_compress(void *dummy, void *dest, void *src,  int size,
+       int block_size, int *error)
+ {
++      uint32_t preset;
+       unsigned char *d = (unsigned char *) dest;
++      struct lzma_xz_options *opts = lzma_xz_get_options();
++
+       lzma_options_lzma opt;
+       lzma_stream strm = LZMA_STREAM_INIT;
+       int res;
+-      lzma_lzma_preset(&opt, LZMA_OPTIONS);
+-      opt.dict_size = block_size;
++      preset = opts->preset;
++
++      if (opts->extreme)
++              preset |= LZMA_PRESET_EXTREME;
++
++      lzma_lzma_preset(&opt, opts->preset);
++      opt.lc = opts->lc;
++      opt.lp = opts->lp;
++      opt.pb = opts->pb;
++      if (opts->fb)
++              opt.nice_len = opts->fb;
++
++      opt.dict_size = opts->dict_size;
+       res = lzma_alone_encoder(&strm, &opt);
+       if(res != LZMA_OK) {
+@@ -143,13 +158,45 @@ failed:
+       return -1;
+ }
++static int lzma_options(char *argv[], int argc)
++{
++      return lzma_xz_options(argv, argc, LZMA_OPT_LZMA);
++}
++
++
++static int lzma_options_post(int block_size)
++{
++      return lzma_xz_options_post(block_size, LZMA_OPT_LZMA);
++}
++
++
++static void *lzma_dump_options(int block_size, int *size)
++{
++      return lzma_xz_dump_options(block_size, size, 0);
++}
++
++
++static int lzma_extract_options(int block_size, void *buffer, int size)
++{
++      return lzma_xz_extract_options(block_size, buffer, size, LZMA_OPT_LZMA);
++}
++
++
++void lzma_usage()
++{
++      lzma_xz_usage(LZMA_OPT_LZMA);
++}
++
+ struct compressor lzma_comp_ops = {
+       .init = NULL,
+       .compress = lzma_compress,
+       .uncompress = lzma_uncompress,
+-      .options = NULL,
+-      .usage = NULL,
++      .options = lzma_options,
++      .options_post = lzma_options_post,
++      .dump_options = lzma_dump_options,
++      .extract_options = lzma_extract_options,
++      .usage = lzma_usage,
+       .id = LZMA_COMPRESSION,
+       .name = "lzma",
+       .supported = 1
+--- a/squashfs-tools/xz_wrapper.h
++++ b/squashfs-tools/xz_wrapper.h
+@@ -24,25 +24,6 @@
+  *
+  */
+-#ifndef linux
+-#define __BYTE_ORDER BYTE_ORDER
+-#define __BIG_ENDIAN BIG_ENDIAN
+-#define __LITTLE_ENDIAN LITTLE_ENDIAN
+-#else
+-#include <endian.h>
+-#endif
+-
+-#if __BYTE_ORDER == __BIG_ENDIAN
+-extern unsigned int inswap_le32(unsigned int);
+-
+-#define SQUASHFS_INSWAP_COMP_OPTS(s) { \
+-      (s)->dictionary_size = inswap_le32((s)->dictionary_size); \
+-      (s)->flags = inswap_le32((s)->flags); \
+-}
+-#else
+-#define SQUASHFS_INSWAP_COMP_OPTS(s)
+-#endif
+-
+ #define MEMLIMIT (32 * 1024 * 1024)
+ struct bcj {
+--- a/squashfs-tools/xz_wrapper.c
++++ b/squashfs-tools/xz_wrapper.c
+@@ -30,6 +30,7 @@
+ #include "squashfs_fs.h"
+ #include "xz_wrapper.h"
+ #include "compressor.h"
++#include "lzma_xz_options.h"
+ static struct bcj bcj[] = {
+       { "x86", LZMA_FILTER_X86, 0 },
+@@ -41,22 +42,18 @@ static struct bcj bcj[] = {
+       { NULL, LZMA_VLI_UNKNOWN, 0 }
+ };
+-static struct comp_opts comp_opts;
+-
+ static int filter_count = 1;
+-static int dictionary_size = 0;
+-static float dictionary_percent = 0;
+ static int xz_options(char *argv[], int argc)
+ {
+-      int i;
+-      char *name;
+-
+       if(strcmp(argv[0], "-Xbcj") == 0) {
++              int i;
++              char *name;
++
+               if(argc < 2) {
+                       fprintf(stderr, "xz: -Xbcj missing filter\n");
+-                      goto failed;
++                      return -2;
+               }
+               name = argv[1];
+@@ -76,190 +73,50 @@ static int xz_options(char *argv[], int 
+                       }
+                       if(bcj[i].name == NULL) {
+                               fprintf(stderr, "xz: -Xbcj unrecognised "
+-                                      "filter\n");
+-                              goto failed;
+-                      }
+-              }
+-      
+-              return 1;
+-      } else if(strcmp(argv[0], "-Xdict-size") == 0) {
+-              char *b;
+-              float size;
+-
+-              if(argc < 2) {
+-                      fprintf(stderr, "xz: -Xdict-size missing dict-size\n");
+-                      goto failed;
+-              }
+-
+-              size = strtof(argv[1], &b);
+-              if(*b == '%') {
+-                      if(size <= 0 || size > 100) {
+-                              fprintf(stderr, "xz: -Xdict-size percentage "
+-                                      "should be 0 < dict-size <= 100\n");
+-                              goto failed;
+-                      }
+-
+-                      dictionary_percent = size;
+-                      dictionary_size = 0;
+-              } else {
+-                      if((float) ((int) size) != size) {
+-                              fprintf(stderr, "xz: -Xdict-size can't be "
+-                                      "fractional unless a percentage of the"
+-                                      " block size\n");
+-                              goto failed;
+-                      }
+-
+-                      dictionary_percent = 0;
+-                      dictionary_size = (int) size;
+-
+-                      if(*b == 'k' || *b == 'K')
+-                              dictionary_size *= 1024;
+-                      else if(*b == 'm' || *b == 'M')
+-                              dictionary_size *= 1024 * 1024;
+-                      else if(*b != '\0') {
+-                              fprintf(stderr, "xz: -Xdict-size invalid "
+-                                      "dict-size\n");
+-                              goto failed;
++                                              "filter\n");
++                              return -2;
+                       }
+               }
+-
+               return 1;
++      } else {
++              return lzma_xz_options(argv, argc, LZMA_OPT_XZ);
+       }
+-
+-      return -1;
+-      
+-failed:
+-      return -2;
+ }
+ static int xz_options_post(int block_size)
+ {
+-      /*
+-       * if -Xdict-size has been specified use this to compute the datablock
+-       * dictionary size
+-       */
+-      if(dictionary_size || dictionary_percent) {
+-              int n;
+-
+-              if(dictionary_size) {
+-                      if(dictionary_size > block_size) {
+-                              fprintf(stderr, "xz: -Xdict-size is larger than"
+-                              " block_size\n");
+-                              goto failed;
+-                      }
+-              } else
+-                      dictionary_size = block_size * dictionary_percent / 100;
+-
+-              if(dictionary_size < 8192) {
+-                      fprintf(stderr, "xz: -Xdict-size should be 8192 bytes "
+-                              "or larger\n");
+-                      goto failed;
+-              }
+-
+-              /*
+-               * dictionary_size must be storable in xz header as either
+-               * 2^n or as  2^n+2^(n+1)
+-              */
+-              n = ffs(dictionary_size) - 1;
+-              if(dictionary_size != (1 << n) && 
+-                              dictionary_size != ((1 << n) + (1 << (n + 1)))) {
+-                      fprintf(stderr, "xz: -Xdict-size is an unsupported "
+-                              "value, dict-size must be storable in xz "
+-                              "header\n");
+-                      fprintf(stderr, "as either 2^n or as 2^n+2^(n+1).  "
+-                              "Example dict-sizes are 75%%, 50%%, 37.5%%, "
+-                              "25%%,\n");
+-                      fprintf(stderr, "or 32K, 16K, 8K etc.\n");
+-                      goto failed;
+-              }
+-
+-      } else
+-              /* No -Xdict-size specified, use defaults */
+-              dictionary_size = block_size;
+-
+-      return 0;
+-
+-failed:
+-      return -1;
++      return lzma_xz_options_post(block_size, LZMA_OPT_XZ);
+ }
+ static void *xz_dump_options(int block_size, int *size)
+ {
+-      int flags = 0, i;
+-
+-      /*
+-       * don't store compressor specific options in file system if the
+-       * default options are being used - no compressor options in the
+-       * file system means the default options are always assumed
+-       *
+-       * Defaults are:
+-       *  metadata dictionary size: SQUASHFS_METADATA_SIZE
+-       *  datablock dictionary size: block_size
+-       *  1 filter
+-       */
+-      if(dictionary_size == block_size && filter_count == 1)
+-              return NULL;
++      int i, flags = 0;
+       for(i = 0; bcj[i].name; i++)
+               flags |= bcj[i].selected << i;
+-      comp_opts.dictionary_size = dictionary_size;
+-      comp_opts.flags = flags;
+-
+-      SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
+-
+-      *size = sizeof(comp_opts);
+-      return &comp_opts;
++      return lzma_xz_dump_options(block_size, size, flags);
+ }
+ static int xz_extract_options(int block_size, void *buffer, int size)
+ {
+-      struct comp_opts *comp_opts = buffer;
+-      int flags, i, n;
+-
+-      if(size == 0) {
+-              /* set defaults */
+-              dictionary_size = block_size;
+-              flags = 0;
+-      } else {
+-              /* check passed comp opts struct is of the correct length */
+-              if(size != sizeof(struct comp_opts))
+-                      goto failed;
+-                                       
+-              SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
+-
+-              dictionary_size = comp_opts->dictionary_size;
+-              flags = comp_opts->flags;
+-
+-              /*
+-               * check that the dictionary size seems correct - the dictionary
+-               * size should 2^n or 2^n+2^(n+1)
+-               */
+-              n = ffs(dictionary_size) - 1;
+-              if(dictionary_size != (1 << n) && 
+-                              dictionary_size != ((1 << n) + (1 << (n + 1))))
+-                      goto failed;
+-      }
++      int ret = lzma_xz_extract_options(block_size, buffer, size, LZMA_OPT_XZ);
+-      filter_count = 1;
+-      for(i = 0; bcj[i].name; i++) {
+-              if((flags >> i) & 1) {
+-                      bcj[i].selected = 1;
+-                      filter_count ++;
+-              } else
+-                      bcj[i].selected = 0;
++      if (!ret) {
++              int i;
++              struct lzma_xz_options *opts = lzma_xz_get_options();
++              for(i = 0; bcj[i].name; i++) {
++                      if((opts->flags >> i) & 1) {
++                              bcj[i].selected = 1;
++                              filter_count ++;
++                      } else
++                              bcj[i].selected = 0;
++              }
+       }
+-
+-      return 0;
+-
+-failed:
+-      fprintf(stderr, "xz: error reading stored compressor options from "
+-              "filesystem!\n");
+-
+-      return -1;
++      return ret;
+ }
+@@ -268,6 +125,7 @@ static int xz_init(void **strm, int bloc
+       int i, j, filters = datablock ? filter_count : 1;
+       struct filter *filter = malloc(filters * sizeof(struct filter));
+       struct xz_stream *stream;
++      struct lzma_xz_options *opts = lzma_xz_get_options();
+       if(filter == NULL)
+               goto failed;
+@@ -281,7 +139,7 @@ static int xz_init(void **strm, int bloc
+       memset(filter, 0, filters * sizeof(struct filter));
+-      stream->dictionary_size = datablock ? dictionary_size :
++      stream->dictionary_size = datablock ? opts->dict_size :
+               SQUASHFS_METADATA_SIZE;
+       filter[0].filter[0].id = LZMA_FILTER_LZMA2;
+@@ -323,14 +181,25 @@ static int xz_compress(void *strm, void 
+         lzma_ret res = 0;
+       struct xz_stream *stream = strm;
+       struct filter *selected = NULL;
++      struct lzma_xz_options *opts = lzma_xz_get_options();
+       stream->filter[0].buffer = dest;
+       for(i = 0; i < stream->filters; i++) {
++              uint32_t preset = opts->preset;
+               struct filter *filter = &stream->filter[i];
+-              if(lzma_lzma_preset(&stream->opt, LZMA_PRESET_DEFAULT))
+-                      goto failed;
++              if (opts->extreme)
++                      preset |= LZMA_PRESET_EXTREME;
++
++        if(lzma_lzma_preset(&stream->opt, preset))
++                      goto failed;
++
++        stream->opt.lc = opts->lc;
++      stream->opt.lp = opts->lp;
++      stream->opt.pb = opts->pb;
++      if (opts->fb)
++              stream->opt.nice_len = opts->fb;
+               stream->opt.dict_size = stream->dictionary_size;
+@@ -384,22 +253,13 @@ static int xz_uncompress(void *dest, voi
+ void xz_usage()
+ {
++      lzma_xz_usage(LZMA_OPT_XZ);
+       fprintf(stderr, "\t  -Xbcj filter1,filter2,...,filterN\n");
+       fprintf(stderr, "\t\tCompress using filter1,filter2,...,filterN in");
+       fprintf(stderr, " turn\n\t\t(in addition to no filter), and choose");
+       fprintf(stderr, " the best compression.\n");
+       fprintf(stderr, "\t\tAvailable filters: x86, arm, armthumb,");
+       fprintf(stderr, " powerpc, sparc, ia64\n");
+-      fprintf(stderr, "\t  -Xdict-size <dict-size>\n");
+-      fprintf(stderr, "\t\tUse <dict-size> as the XZ dictionary size.  The");
+-      fprintf(stderr, " dictionary size\n\t\tcan be specified as a");
+-      fprintf(stderr, " percentage of the block size, or as an\n\t\t");
+-      fprintf(stderr, "absolute value.  The dictionary size must be less");
+-      fprintf(stderr, " than or equal\n\t\tto the block size and 8192 bytes");
+-      fprintf(stderr, " or larger.  It must also be\n\t\tstorable in the xz");
+-      fprintf(stderr, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
+-      fprintf(stderr, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
+-      fprintf(stderr, " 32K, 16K, 8K\n\t\tetc.\n");
+ }
+--- a/squashfs-tools/Makefile
++++ b/squashfs-tools/Makefile
+@@ -140,6 +140,8 @@ COMPRESSORS += xz
+ endif
+ ifneq ($(LZMA_XZ_SUPPORT)$(XZ_SUPPORT),)
++MKSQUASHFS_OBJS += lzma_xz_options.o
++UNSQUASHFS_OBJS += lzma_xz_options.o
+ ifneq ($(LZMA_LIB),)
+ MKSQUASHFS_OBJS += $(LZMA_LIB)
+ UNSQUASHFS_OBJS += $(LZMA_LIB)