Error Box::read()

in libheif/box.cc [447:822]


Error Box::read(BitstreamRange& range, std::shared_ptr<Box>* result)
{
  BoxHeader hdr;
  Error err = hdr.parse_header(range);
  if (err) {
    return err;
  }

  if (range.error()) {
    return range.get_error();
  }

  std::shared_ptr<Box> box;

  switch (hdr.get_short_type()) {
    case fourcc("ftyp"):
      box = std::make_shared<Box_ftyp>();
      break;

    case fourcc("meta"):
      box = std::make_shared<Box_meta>();
      break;

    case fourcc("hdlr"):
      box = std::make_shared<Box_hdlr>();
      break;

    case fourcc("pitm"):
      box = std::make_shared<Box_pitm>();
      break;

    case fourcc("iloc"):
      box = std::make_shared<Box_iloc>();
      break;

    case fourcc("iinf"):
      box = std::make_shared<Box_iinf>();
      break;

    case fourcc("infe"):
      box = std::make_shared<Box_infe>();
      break;

    case fourcc("iprp"):
      box = std::make_shared<Box_iprp>();
      break;

    case fourcc("ipco"):
      box = std::make_shared<Box_ipco>();
      break;

    case fourcc("ipma"):
      box = std::make_shared<Box_ipma>();
      break;

    case fourcc("ispe"):
      box = std::make_shared<Box_ispe>();
      break;

    case fourcc("auxC"):
      box = std::make_shared<Box_auxC>();
      break;

    case fourcc("irot"):
      box = std::make_shared<Box_irot>();
      break;

    case fourcc("imir"):
      box = std::make_shared<Box_imir>();
      break;

    case fourcc("clap"):
      box = std::make_shared<Box_clap>();
      break;

    case fourcc("iref"):
      box = std::make_shared<Box_iref>();
      break;

    case fourcc("hvcC"):
      box = std::make_shared<Box_hvcC>();
      break;

    case fourcc("av1C"):
      box = std::make_shared<Box_av1C>();
      break;

    case fourcc("vvcC"):
      box = std::make_shared<Box_vvcC>();
      break;

    case fourcc("idat"):
      box = std::make_shared<Box_idat>();
      break;

    case fourcc("grpl"):
      box = std::make_shared<Box_grpl>();
      break;

    case fourcc("pymd"):
      box = std::make_shared<Box_pymd>();
      break;

    case fourcc("altr"):
      box = std::make_shared<Box_EntityToGroup>();
      break;

    case fourcc("ster"):
      box = std::make_shared<Box_ster>();
      break;

    case fourcc("dinf"):
      box = std::make_shared<Box_dinf>();
      break;

    case fourcc("dref"):
      box = std::make_shared<Box_dref>();
      break;

    case fourcc("url "):
      box = std::make_shared<Box_url>();
      break;

    case fourcc("colr"):
      box = std::make_shared<Box_colr>();
      break;

    case fourcc("pixi"):
      box = std::make_shared<Box_pixi>();
      break;

    case fourcc("pasp"):
      box = std::make_shared<Box_pasp>();
      break;

    case fourcc("lsel"):
      box = std::make_shared<Box_lsel>();
      break;

    case fourcc("a1op"):
      box = std::make_shared<Box_a1op>();
      break;

    case fourcc("a1lx"):
      box = std::make_shared<Box_a1lx>();
      break;

    case fourcc("clli"):
      box = std::make_shared<Box_clli>();
      break;

    case fourcc("mdcv"):
      box = std::make_shared<Box_mdcv>();
      break;

    case fourcc("cmin"):
      box = std::make_shared<Box_cmin>();
      break;

    case fourcc("cmex"):
      box = std::make_shared<Box_cmex>();
      break;

    case fourcc("udes"):
      box = std::make_shared<Box_udes>();
      break;

    case fourcc("jpgC"):
      box = std::make_shared<Box_jpgC>();
      break;

#if WITH_UNCOMPRESSED_CODEC
    case fourcc("cmpd"):
      box = std::make_shared<Box_cmpd>();
      break;

    case fourcc("uncC"):
      box = std::make_shared<Box_uncC>();
      break;

    case fourcc("cmpC"):
      box = std::make_shared<Box_cmpC>();
      break;

    case fourcc("icbr"):
      box = std::make_shared<Box_icbr>();
      break;
#endif

    // --- JPEG 2000
      
    case fourcc("j2kH"):
      box = std::make_shared<Box_j2kH>();
      break;

    case fourcc("cdef"):
      box = std::make_shared<Box_cdef>();
      break;

    case fourcc("cmap"):
      box = std::make_shared<Box_cmap>();
      break;

    case fourcc("pclr"):
      box = std::make_shared<Box_pclr>();
      break;

    case fourcc("j2kL"):
      box = std::make_shared<Box_j2kL>();
      break;

    // --- mski
      
    case fourcc("mskC"):
      box = std::make_shared<Box_mskC>();
      break;

    // --- AVC (H.264)

    case fourcc("avcC"):
      box = std::make_shared<Box_avcC>();
      break;

    case fourcc("mdat"):
      // avoid generating a 'Box_other'
      box = std::make_shared<Box>();
      break;

    case fourcc("uuid"):
      if (hdr.get_uuid_type() == std::vector<uint8_t>{0x22, 0xcc, 0x04, 0xc7, 0xd6, 0xd9, 0x4e, 0x07, 0x9d, 0x90, 0x4e, 0xb6, 0xec, 0xba, 0xf3, 0xa3}) {
        box = std::make_shared<Box_cmin>();
      }
      else if (hdr.get_uuid_type() == std::vector<uint8_t>{0x43, 0x63, 0xe9, 0x14, 0x5b, 0x7d, 0x4a, 0xab, 0x97, 0xae, 0xbe, 0xa6, 0x98, 0x03, 0xb4, 0x34}) {
        box = std::make_shared<Box_cmex>();
      }
      else {
        box = std::make_shared<Box_other>(hdr.get_short_type());
      }
      break;

    case fourcc("moov"):
      box = std::make_shared<Box_moov>();
      break;

    case fourcc("mvhd"):
      box = std::make_shared<Box_mvhd>();
      break;

    case fourcc("trak"):
      box = std::make_shared<Box_trak>();
      break;

    case fourcc("tkhd"):
      box = std::make_shared<Box_tkhd>();
      break;

    case fourcc("mdia"):
      box = std::make_shared<Box_mdia>();
      break;

    case fourcc("mdhd"):
      box = std::make_shared<Box_mdhd>();
      break;

    case fourcc("minf"):
      box = std::make_shared<Box_minf>();
      break;

    case fourcc("vmhd"):
      box = std::make_shared<Box_vmhd>();
      break;

    case fourcc("stbl"):
      box = std::make_shared<Box_stbl>();
      break;

    case fourcc("stsd"):
      box = std::make_shared<Box_stsd>();
      break;

    case fourcc("hvc1"):
      box = std::make_shared<Box_hvc1>();
      break;

    case fourcc("ccst"):
      box = std::make_shared<Box_ccst>();
      break;

    case fourcc("stsz"):
      box = std::make_shared<Box_stsz>();
      break;

    case fourcc("stts"):
      box = std::make_shared<Box_stts>();
      break;

    case fourcc("stsc"):
      box = std::make_shared<Box_stsc>();
      break;

    case fourcc("stco"):
      box = std::make_shared<Box_stco>();
      break;
      
    case fourcc("stss"):
      box = std::make_shared<Box_stss>();
      break;

    default:
      box = std::make_shared<Box_other>(hdr.get_short_type());
      break;
  }

  box->set_short_header(hdr);

  if (hdr.has_fixed_box_size() && hdr.get_box_size() < hdr.get_header_size()) {
    std::stringstream sstr;
    sstr << "Box size (" << hdr.get_box_size() << " bytes) smaller than header size ("
         << hdr.get_header_size() << " bytes)";

    // Sanity check.
    return Error(heif_error_Invalid_input,
                 heif_suberror_Invalid_box_size,
                 sstr.str());
  }


  if (range.get_nesting_level() > MAX_BOX_NESTING_LEVEL) {
    return Error(heif_error_Memory_allocation_error,
                 heif_suberror_Security_limit_exceeded,
                 "Security limit for maximum nesting of boxes has been exceeded");
  }


  if (hdr.has_fixed_box_size()) {
    auto status = range.wait_for_available_bytes(hdr.get_box_size() - hdr.get_header_size());
    if (status != StreamReader::size_reached) {
      // TODO: return recoverable error at timeout
      return Error(heif_error_Invalid_input,
                   heif_suberror_End_of_data);
    }
  }

  // Security check: make sure that box size does not exceed int64 size.

  if (hdr.get_box_size() > (uint64_t) std::numeric_limits<int64_t>::max()) {
    return Error(heif_error_Invalid_input,
                 heif_suberror_Invalid_box_size);
  }

  int64_t box_size = static_cast<int64_t>(hdr.get_box_size());
  int64_t box_size_without_header = hdr.has_fixed_box_size() ? (box_size - hdr.get_header_size()) : (int64_t)range.get_remaining_bytes();

  // Box size may not be larger than remaining bytes in parent box.

  if ((int64_t)range.get_remaining_bytes() < box_size_without_header) {
    return Error(heif_error_Invalid_input,
                 heif_suberror_Invalid_box_size);
  }


  // Create child bitstream range and read box from that range.

  BitstreamRange boxrange(range.get_istream(),
                          box_size_without_header,
                          &range);

  err = box->parse(boxrange);
  if (err == Error::Ok) {
    *result = std::move(box);
  }

  boxrange.skip_to_end_of_box();

  return err;
}