"Fossies" - the Fresh Open Source Software Archive

Member "libisofs-1.5.4/libisofs/rockridge_read.c" (29 Oct 2020, 19027 Bytes) of package /linux/misc/libisofs-1.5.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "rockridge_read.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /*
    2  * Copyright (c) 2007 Vreixo Formoso
    3  * Copyright (c) 2009 Thomas Schmitt
    4  * 
    5  * This file is part of the libisofs project; you can redistribute it and/or 
    6  * modify it under the terms of the GNU General Public License version 2 
    7  * or later as published by the Free Software Foundation. 
    8  * See COPYING file for details.
    9  */
   10 
   11 /*
   12  * This file contains functions related to the reading of SUSP, 
   13  * Rock Ridge and AAIP extensions on an ECMA-119 image.
   14  */
   15 
   16 #ifdef HAVE_CONFIG_H
   17 #include "../config.h"
   18 #endif
   19 
   20 #include "libisofs.h"
   21 #include "ecma119.h"
   22 #include "util.h"
   23 #include "rockridge.h"
   24 #include "messages.h"
   25 
   26 #include <sys/stat.h>
   27 #include <stdlib.h>
   28 #include <string.h>
   29 
   30 struct susp_iterator
   31 {
   32     uint8_t* base;
   33     int pos;
   34     int size;
   35     IsoDataSource *src;
   36     int msgid;
   37 
   38     /* Number of blocks in the ISO 9660 filesystem */
   39     uint32_t fs_blocks;
   40 
   41     /* block and offset for next continuation area */
   42     uint32_t ce_block;
   43     uint32_t ce_off;
   44     
   45     /** Length of the next continuation area, 0 if no more CA are specified */
   46     uint32_t ce_len; 
   47 
   48     uint8_t *buffer; /*< If there are continuation areas */
   49 };
   50 
   51 SuspIterator*
   52 susp_iter_new(IsoDataSource *src, struct ecma119_dir_record *record,
   53               uint32_t fs_blocks, uint8_t len_skp, int msgid)
   54 {
   55     int pad = (record->len_fi[0] + 1) % 2;
   56     struct susp_iterator *iter = malloc(sizeof(struct susp_iterator));
   57     if (iter == NULL) {
   58         return NULL;
   59     }
   60 
   61     iter->base = record->file_id + record->len_fi[0] + pad;
   62     iter->pos = len_skp; /* 0 in most cases */
   63     iter->size = record->len_dr[0] - record->len_fi[0] - 33 - pad;
   64     iter->src = src;
   65     iter->msgid = msgid;
   66     iter->fs_blocks = fs_blocks;
   67 
   68     iter->ce_len = 0;
   69     iter->buffer = NULL;
   70 
   71     return iter;
   72 }
   73 
   74 /* More than 1 MiB in a single file's CE area is suspicious */
   75 #define ISO_SUSP_MAX_CE_BYTES (1024 * 1024)
   76 
   77 
   78 /* @param flag bit0 = First call on root:
   79                       Not yet clear whether this is SUSP at all
   80 */
   81 int susp_iter_next(SuspIterator *iter, struct susp_sys_user_entry **sue,
   82                    int flag)
   83 {
   84     struct susp_sys_user_entry *entry;
   85 
   86     entry = (struct susp_sys_user_entry*)(iter->base + iter->pos);
   87 
   88     if (flag & 1) {
   89         /* Yet unclear whether it is SUSP at all */
   90         if (iter->size < 7)
   91             return 0;
   92         if (!SUSP_SIG(entry, 'S', 'P'))
   93             return 0;
   94         if (entry->len_sue[0] < 7)
   95             return 0;
   96         /* Looks like SUSP enough to pass the further processing here. */
   97     }
   98     if ( (iter->pos + 4 > iter->size) || (SUSP_SIG(entry, 'S', 'T'))) {
   99 
  100         /* 
  101          * End of the System Use Area or Continuation Area.
  102          * Note that ST is not needed when the space left is less than 4.
  103          * (IEEE 1281, SUSP. section 4) 
  104          */
  105         if (iter->ce_len) {
  106             uint32_t block, nblocks, skipped_blocks, skipped_bytes;
  107 
  108             /* A CE was found, there is another continuation area */
  109             skipped_blocks = iter->ce_off / BLOCK_SIZE;
  110             skipped_bytes = skipped_blocks * BLOCK_SIZE;
  111             nblocks = DIV_UP(iter->ce_off - skipped_bytes + iter->ce_len,
  112                              BLOCK_SIZE);
  113             if (nblocks <= 0 || iter->ce_len > ISO_SUSP_MAX_CE_BYTES)
  114                 return ISO_SUSP_WRONG_CE_SIZE;
  115             if (((uint64_t) iter->ce_block) + skipped_blocks + nblocks >
  116                 (uint64_t) iter->fs_blocks)
  117                 return ISO_SUSP_WRONG_CE_SIZE;
  118             iter->buffer = realloc(iter->buffer, nblocks * BLOCK_SIZE);
  119 
  120             /* Read blocks needed to cache the given CE area range */
  121             for (block = 0; block < nblocks; ++block) {
  122                 int ret;
  123                 ret = iter->src->read_block(iter->src,
  124                                        iter->ce_block + skipped_blocks + block,
  125                                        iter->buffer + block * BLOCK_SIZE);
  126                 if (ret < 0) {
  127                     return ret;
  128                 }
  129             }
  130             iter->base = iter->buffer + (iter->ce_off - skipped_bytes);
  131             iter->pos = 0;
  132             iter->size = iter->ce_len;
  133             iter->ce_len = 0;
  134             entry = (struct susp_sys_user_entry*)iter->base;
  135         } else {
  136             return 0;
  137         }
  138     }
  139 
  140     if (entry->len_sue[0] == 0) {
  141         /* a wrong image with this lead us to a infinity loop */
  142         iso_msg_submit(iter->msgid, ISO_WRONG_RR, 0,
  143                       "Damaged RR/SUSP information.");
  144         return ISO_WRONG_RR;
  145     }
  146 
  147     iter->pos += entry->len_sue[0];
  148 
  149     if (SUSP_SIG(entry, 'C', 'E')) {
  150         /* Continuation entry */
  151         if (iter->ce_len) {
  152             int ret;
  153             ret = iso_msg_submit(iter->msgid, ISO_UNSUPPORTED_SUSP, 0,
  154                 "More than one CE System user entry has found in a single "
  155                 "System Use field or continuation area. This breaks SUSP "
  156                 "standard and it's not supported. Ignoring last CE. Maybe "
  157                 "the image is damaged.");
  158             if (ret < 0) {
  159                 return ret;
  160             }
  161         } else {
  162             iter->ce_block = iso_read_bb(entry->data.CE.block, 4, NULL);
  163             iter->ce_off = iso_read_bb(entry->data.CE.offset, 4, NULL);
  164             iter->ce_len = iso_read_bb(entry->data.CE.len, 4, NULL);
  165         }
  166 
  167         /* we don't want to return CE entry to the user */
  168         return susp_iter_next(iter, sue, 0);
  169     } else if (SUSP_SIG(entry, 'P', 'D')) {
  170         /* skip padding */
  171         return susp_iter_next(iter, sue, 0);
  172     }
  173 
  174     *sue = entry;
  175     return ISO_SUCCESS;
  176 }
  177 
  178 void susp_iter_free(SuspIterator *iter)
  179 {
  180     free(iter->buffer);
  181     free(iter);
  182 }
  183 
  184 /**
  185  * Fills a struct stat with the values of a Rock Ridge PX entry (RRIP, 4.1.1).
  186  * 
  187  * @return 
  188  *      1 on success, < 0 on error
  189  */
  190 int read_rr_PX(struct susp_sys_user_entry *px, struct stat *st)
  191 {
  192     if (px == NULL || st == NULL) {
  193         return ISO_NULL_POINTER;
  194     }
  195     if (px->sig[0] != 'P' || px->sig[1] != 'X') {
  196         return ISO_WRONG_ARG_VALUE;
  197     }
  198     
  199     if (px->len_sue[0] != 44 && px->len_sue[0] != 36) {
  200         return ISO_WRONG_RR;
  201     }
  202     
  203     st->st_mode = iso_read_bb(px->data.PX.mode, 4, NULL);
  204     st->st_nlink = iso_read_bb(px->data.PX.links, 4, NULL);
  205     st->st_uid = iso_read_bb(px->data.PX.uid, 4, NULL);
  206     st->st_gid = iso_read_bb(px->data.PX.gid, 4, NULL);
  207     st->st_ino = 0;
  208     if (px->len_sue[0] == 44) {
  209         /* this corresponds to RRIP 1.12, so we have inode serial number */
  210         st->st_ino = iso_read_bb(px->data.PX.serial, 4, NULL);
  211         /* Indicate that st_ino is valid */
  212         return 2;
  213     }
  214     return 1;
  215 }
  216 
  217 /**
  218  * Fills a struct stat with the values of a Rock Ridge TF entry (RRIP, 4.1.6)
  219  * 
  220  * @return 
  221  *      1 on success, < 0 on error
  222  */
  223 int read_rr_TF(struct susp_sys_user_entry *tf, struct stat *st)
  224 {
  225     time_t time;
  226     int s;
  227     int nts = 0;
  228     
  229     if (tf == NULL || st == NULL) {
  230         return ISO_NULL_POINTER;
  231     }
  232     if (tf->sig[0] != 'T' || tf->sig[1] != 'F') {
  233         return ISO_WRONG_ARG_VALUE;
  234     }
  235     
  236     if (tf->data.TF.flags[0] & (1 << 7)) {
  237         /* long form */
  238         s = 17;
  239     } else {
  240         s = 7;
  241     }
  242     
  243     /* 1. Creation time */
  244     if (tf->data.TF.flags[0] & (1 << 0)) {
  245         /* Linux accepts ctime by Creation time and by Attributes time.
  246          * If both are given, then Attribute time will win.
  247          */
  248         if (tf->len_sue[0] < 5 + (nts+1) * s) {
  249             /* RR TF entry too short. */
  250             return ISO_WRONG_RR;
  251         }
  252         if (s == 7) {
  253             time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
  254         } else {
  255             time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
  256         }
  257         st->st_ctime = time;
  258         ++nts;
  259     }
  260     
  261     /* 2. modify time */
  262     if (tf->data.TF.flags[0] & (1 << 1)) {
  263         if (tf->len_sue[0] < 5 + (nts+1) * s) {
  264             /* RR TF entry too short. */
  265             return ISO_WRONG_RR;
  266         }
  267         if (s == 7) {
  268             time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
  269         } else {
  270             time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
  271         }
  272         st->st_mtime = time;
  273         ++nts;
  274     }
  275     
  276     /* 3. access time */
  277     if (tf->data.TF.flags[0] & (1 << 2)) {
  278         if (tf->len_sue[0] < 5 + (nts+1) * s) {
  279             /* RR TF entry too short. */
  280             return ISO_WRONG_RR;
  281         }
  282         if (s == 7) {
  283             time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
  284         } else {
  285             time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
  286         }
  287         st->st_atime = time;
  288         ++nts;
  289     }
  290     
  291     /* 4. attributes time */
  292     if (tf->data.TF.flags[0] & (1 << 3)) {
  293         if (tf->len_sue[0] < 5 + (nts+1) * s) {
  294             /* RR TF entry too short. */
  295             return ISO_WRONG_RR;
  296         }
  297         if (s == 7) {
  298             time = iso_datetime_read_7(&tf->data.TF.t_stamps[nts*7]);
  299         } else {
  300             time = iso_datetime_read_17(&tf->data.TF.t_stamps[nts*17]);
  301         }
  302         st->st_ctime = time;
  303         ++nts;
  304     }
  305     
  306     /* we ignore backup, expire and effect times */
  307     
  308     return ISO_SUCCESS;
  309 }
  310 
  311 /**
  312  * Read a RR NM entry (RRIP, 4.1.4), and appends the name stored there to
  313  * the given name. You can pass a pointer to NULL as name.
  314  * 
  315  * @return
  316  *      1 on success, < 0 on error
  317  */
  318 int read_rr_NM(struct susp_sys_user_entry *nm, char **name, int *cont)
  319 {
  320     if (nm == NULL || name == NULL) {
  321         return ISO_NULL_POINTER;
  322     }
  323     if (nm->sig[0] != 'N' || nm->sig[1] != 'M') {
  324         return ISO_WRONG_ARG_VALUE;
  325     }
  326     
  327     if (nm->len_sue[0] == 5) {
  328         if (nm->data.NM.flags[0] & 0x2) {
  329             /* it is a "." entry */
  330             if (*name == NULL) {
  331                 return ISO_SUCCESS;
  332             } else {
  333                 /* we can't have a previous not-NULL name */
  334                 return ISO_WRONG_RR;
  335             }
  336         }
  337     }
  338     
  339     if (nm->len_sue[0] <= 5) {
  340         /* ".." entry is an error, as we will never call it */
  341         return ISO_WRONG_RR;
  342     }
  343         
  344     /* concatenate the results */
  345     if (*cont) {
  346         *name = realloc(*name, strlen(*name) + nm->len_sue[0] - 5 + 1);
  347         strncat(*name, (char*)nm->data.NM.name, nm->len_sue[0] - 5);
  348     } else {
  349         *name = iso_util_strcopy((char*)nm->data.NM.name, nm->len_sue[0] - 5);
  350     }
  351     if (*name == NULL) {
  352         return ISO_OUT_OF_MEM;
  353     }
  354 
  355     /* and set cond according to the value of CONTINUE flag */
  356     *cont = nm->data.NM.flags[0] & 0x01;
  357     return ISO_SUCCESS;
  358 }
  359 
  360 /**
  361  * Read a SL RR entry (RRIP, 4.1.3), checking if the destination continues.
  362  * 
  363  * @param cont
  364  *      0 not continue, 1 continue, 2 continue component 
  365  * @return
  366  *      1 on success, < 0 on error
  367  */
  368 int read_rr_SL(struct susp_sys_user_entry *sl, char **dest, int *cont)
  369 {
  370     int pos;
  371     
  372     if (sl == NULL || dest == NULL) {
  373         return ISO_NULL_POINTER;
  374     }
  375     if (sl->sig[0] != 'S' || sl->sig[1] != 'L') {
  376         return ISO_WRONG_ARG_VALUE;
  377     }
  378     
  379     for (pos = 0; pos + 5 < sl->len_sue[0]; 
  380         pos += 2 + sl->data.SL.comps[pos + 1]) {
  381         char *comp;
  382         uint8_t len;
  383         uint8_t flags = sl->data.SL.comps[pos];
  384         
  385         if (flags & 0x2) {
  386             /* current directory */
  387             len = 1;
  388             comp = ".";
  389         } else if (flags & 0x4) {
  390             /* parent directory */
  391             len = 2;
  392             comp = "..";
  393         } else if (flags & 0x8) {
  394             /* root directory */
  395             len = 1;
  396             comp = "/";
  397         } else if (flags & ~0x01) {
  398             /* unsupported flag component */
  399             return ISO_UNSUPPORTED_RR;
  400         } else {
  401             len = sl->data.SL.comps[pos + 1];
  402             comp = (char*)&sl->data.SL.comps[pos + 2];
  403         } 
  404         
  405         if (*cont == 1) {
  406             /* new component */
  407             size_t size = strlen(*dest);
  408             int has_slash;
  409 
  410             *dest = realloc(*dest, strlen(*dest) + len + 2);
  411             if (*dest == NULL) {
  412                 return ISO_OUT_OF_MEM;
  413             }
  414             /* it is a new compoenent, add the '/' */
  415             has_slash = 0;
  416             if (size > 0)
  417                 if ((*dest)[size - 1] == '/')
  418                     has_slash = 1;
  419             if (!has_slash) {
  420                 (*dest)[size] = '/';
  421                 (*dest)[size+1] = '\0';
  422             }
  423             strncat(*dest, comp, len);
  424         } else if (*cont == 2) {
  425             /* the component continues */
  426             *dest = realloc(*dest, strlen(*dest) + len + 1);
  427             if (*dest == NULL) {
  428                 return ISO_OUT_OF_MEM;
  429             }
  430             /* we don't have to add the '/' */
  431             strncat(*dest, comp, len);
  432         } else {
  433             *dest = iso_util_strcopy(comp, len);
  434         }
  435         if (*dest == NULL) {
  436             return ISO_OUT_OF_MEM;
  437         }
  438         /* do the component continue or not? */
  439         *cont = (flags & 0x01) ? 2 : 1;
  440     }
  441     
  442     if (*cont == 2) {
  443         /* TODO check that SL flag is set to continute too ?*/
  444     } else {
  445         *cont = sl->data.SL.flags[0] & 0x1 ? 1 : 0;
  446     }
  447     
  448     return ISO_SUCCESS;
  449 }
  450 
  451 /**
  452  * Fills a struct stat with the values of a Rock Ridge PN entry (RRIP, 4.1.2).
  453  * 
  454  * @return 
  455  *      1 on success, < 0 on error
  456  */
  457 int read_rr_PN(struct susp_sys_user_entry *pn, struct stat *st)
  458 {
  459     int high_shift= 0;
  460 
  461     if (pn == NULL || st == NULL) {
  462         return ISO_NULL_POINTER;
  463     }
  464     if (pn->sig[0] != 'P' || pn->sig[1] != 'N') {
  465         return ISO_WRONG_ARG_VALUE;
  466     }
  467     
  468     if (pn->len_sue[0] != 20) {
  469         return ISO_WRONG_RR;
  470     }
  471 
  472     /* (dev_t << 32) causes compiler warnings on FreeBSD
  473         because sizeof(dev_t) is 4.
  474     */
  475     st->st_rdev = (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
  476     if (sizeof(st->st_rdev) > 4) {
  477         high_shift = 32;
  478         st->st_rdev |= (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) <<
  479                                high_shift);
  480     }
  481 
  482 /* was originally:
  483     st->st_rdev = (dev_t)((dev_t)iso_read_bb(pn->data.PN.high, 4, NULL) << 32)
  484                   | (dev_t)iso_read_bb(pn->data.PN.low, 4, NULL);
  485 */
  486 
  487     return ISO_SUCCESS;
  488 }
  489 
  490 
  491 /* AA is the obsolete field signature of AAIP versions < 2.0
  492 */
  493 int read_aaip_AA(struct susp_sys_user_entry *sue,
  494                  unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
  495                  size_t *prev_field, int *is_done, int flag)
  496 {
  497      unsigned char *aapt;
  498 
  499      if (*is_done) {
  500 
  501          /* To coexist with Apple ISO :
  502             Gracefully react on possibly trailing Apple AA
  503          */
  504          if (sue->version[0] != 1 || sue->len_sue[0] == 7)
  505              return ISO_SUCCESS;
  506 
  507          return ISO_WRONG_RR;
  508      }
  509      if (*aa_size == 0 || *aa_string == NULL) {
  510          /* Gracefully react on possibly leading Apple AA
  511          */
  512          if (sue->version[0] != 1 || sue->len_sue[0] < 9)
  513              return ISO_SUCCESS;
  514      }
  515 
  516      /* A valid AAIP AA entry has 5 header bytes and at least 1 component byte
  517       */
  518      if (sue->len_sue[0] < 6)
  519          return ISO_WRONG_RR;
  520 
  521      /* Possibly create or grow storage */
  522      if (*aa_size == 0 || *aa_string == NULL) {
  523          *aa_size = *aa_len + sue->len_sue[0];
  524          *aa_string = calloc(*aa_size, 1);
  525          *aa_len = 0;
  526      } else if (*aa_len + sue->len_sue[0] > *aa_size) {
  527 
  528          if (sue->version[0] != 1) {
  529              /* Apple ISO within the AAIP field group is not AAIP compliant
  530              */
  531              return ISO_WRONG_RR;
  532          }
  533 
  534          *aa_size += *aa_len + sue->len_sue[0];
  535          *aa_string = realloc(*aa_string, *aa_size);
  536      }
  537      if (*aa_string == NULL)
  538          return ISO_OUT_OF_MEM;
  539 
  540      if (*aa_len > 0) {
  541          /* Mark prev_field as being continued */
  542          (*aa_string)[*prev_field + 4] = 1;
  543      }
  544 
  545      *prev_field = *aa_len;
  546 
  547      /* Compose new SUSP header with signature aa[], cont == 0 */
  548      aapt = *aa_string + *aa_len;
  549 
  550      aapt[0] = 'A';
  551      aapt[1] = 'L';
  552      aapt[2] = sue->len_sue[0];
  553      aapt[3] = 1;
  554      aapt[4] = 0;
  555 
  556      /* Append sue payload */
  557      memcpy(aapt + 5, sue->data.AL.comps, sue->len_sue[0] - 5);
  558      *is_done = !(sue->data.AL.flags[0] & 1);
  559      *aa_len += sue->len_sue[0];
  560 
  561      return ISO_SUCCESS;
  562 }
  563 
  564 
  565 /* AL is the field signature of AAIP versions >= 2.0
  566 */
  567 int read_aaip_AL(struct susp_sys_user_entry *sue,
  568                  unsigned char **aa_string, size_t *aa_size, size_t *aa_len,
  569                  size_t *prev_field, int *is_done, int flag)
  570 {
  571      unsigned char *aapt;
  572 
  573      if (*is_done)
  574          return ISO_WRONG_RR;
  575      if (sue->version[0] != 1)
  576          return ISO_WRONG_RR;
  577 
  578      /* A valid AL entry has 5 header bytes and at least 1 component byte
  579       */
  580      if (sue->len_sue[0] < 6)
  581          return ISO_WRONG_RR;
  582 
  583      /* Possibly create or grow storage */
  584      if (*aa_size == 0 || *aa_string == NULL) {
  585          *aa_size = *aa_len + sue->len_sue[0];
  586          *aa_string = calloc(*aa_size, 1);
  587          *aa_len = 0;
  588      } else if (*aa_len + sue->len_sue[0] > *aa_size) {
  589          *aa_size += *aa_len + sue->len_sue[0];
  590          *aa_string = realloc(*aa_string, *aa_size);
  591      }
  592      if (*aa_string == NULL)
  593          return ISO_OUT_OF_MEM;
  594 
  595      if (*aa_len > 0) {
  596          /* Mark prev_field as being continued */
  597          (*aa_string)[*prev_field + 4] = 1;
  598      }
  599 
  600      *prev_field = *aa_len;
  601 
  602      /* Compose new SUSP header with signature aa[], cont == 0 */
  603      aapt = *aa_string + *aa_len;
  604 
  605      aapt[0] = 'A';
  606      aapt[1] = 'L';
  607      aapt[2] = sue->len_sue[0];
  608      aapt[3] = 1;
  609      aapt[4] = 0;
  610 
  611      /* Append sue payload */
  612      memcpy(aapt + 5, sue->data.AL.comps, sue->len_sue[0] - 5);
  613      *is_done = !(sue->data.AL.flags[0] & 1);
  614      *aa_len += sue->len_sue[0];
  615 
  616      return ISO_SUCCESS;
  617 }
  618 
  619 /**
  620  * Reads the zisofs parameters from a ZF field (see doc/zisofs_format.txt
  621  * and doc/zisofs2_format.txt).
  622  * 
  623  * @return 
  624  *      1 on success, < 0 on error
  625  */
  626 int read_zisofs_ZF(struct susp_sys_user_entry *zf, uint8_t algorithm[2],
  627                    uint8_t *header_size_div4, uint8_t *block_size_log2,
  628                    uint64_t *uncompressed_size, int flag)
  629 {
  630     if (zf == NULL) {
  631         return ISO_NULL_POINTER;
  632     }
  633     if ((zf->sig[0] != 'Z' || zf->sig[1] != 'F') &&
  634         (zf->sig[0] != 'Z' || zf->sig[1] != '2'))
  635         return ISO_WRONG_ARG_VALUE;
  636     if (zf->len_sue[0] != 16) {
  637         return ISO_WRONG_RR;
  638     }
  639     if (zf->version[0] > 2)
  640         return ISO_WRONG_RR;
  641     algorithm[0] = zf->data.ZF.parameters[0];
  642     algorithm[1] = zf->data.ZF.parameters[1];
  643     *header_size_div4 = zf->data.ZF.parameters[2];
  644     *block_size_log2 = zf->data.ZF.parameters[3];
  645     if (zf->version[0] == 1)
  646         *uncompressed_size = iso_read_bb(&(zf->data.ZF.parameters[4]), 4,
  647                                          NULL);
  648     else
  649         *uncompressed_size = iso_read_lsb64(&(zf->data.ZF.parameters[4]));
  650     return ISO_SUCCESS;
  651 }
  652 
  653