예제 #1
0
  /** Reads a WAVE Chunk. */
  protected boolean readChunk(RepInfo info) throws IOException {
    Chunk chunk = null;
    ChunkHeader chunkh = new ChunkHeader(this, info);
    if (!chunkh.readHeader(_dstream)) {
      return false;
    }
    int chunkSize = (int) chunkh.getSize();
    bytesRemaining -= chunkSize + 8;

    if (bytesRemaining < 0) {
      info.setMessage(new ErrorMessage("Invalid chunk size", _nByte));
      return false;
    }

    String id = chunkh.getID();
    if ("fmt ".equals(id)) {
      if (formatChunkSeen) {
        dupChunkError(info, "Format");
      }
      chunk = new FormatChunk(this, chunkh, _dstream);
      formatChunkSeen = true;
    } else if ("data".equals(id)) {
      if (dataChunkSeen) {
        dupChunkError(info, "Data");
      }
      chunk = new DataChunk(this, chunkh, _dstream);
      dataChunkSeen = true;
    } else if ("fact".equals(id)) {
      chunk = new FactChunk(this, chunkh, _dstream);
      factChunkSeen = true;
      // Are multiple 'fact' chunks allowed?
    } else if ("note".equals(id)) {
      chunk = new NoteChunk(this, chunkh, _dstream);
      // Multiple note chunks are allowed
    } else if ("labl".equals(id)) {
      chunk = new LabelChunk(this, chunkh, _dstream);
      // Multiple label chunks are allowed
    } else if ("list".equals(id)) {
      chunk = new AssocDataListChunk(this, chunkh, _dstream, info);
      // Are multiple chunks allowed?  Who knows?
    } else if ("LIST".equals(id)) {
      chunk = new ListInfoChunk(this, chunkh, _dstream, info);
      // Multiple list chunks must be OK, since there can
      // be different types, e.g., an INFO list and an exif list.
    } else if ("smpl".equals(id)) {
      chunk = new SampleChunk(this, chunkh, _dstream);
      // Multiple sample chunks are allowed -- I think
    } else if ("inst".equals(id)) {
      if (instrumentChunkSeen) {
        dupChunkError(info, "Instrument");
      }
      chunk = new InstrumentChunk(this, chunkh, _dstream);
      // Only one instrument chunk is allowed
      instrumentChunkSeen = true;
    } else if ("mext".equals(id)) {
      if (mpegChunkSeen) {
        dupChunkError(info, "MPEG");
      }
      chunk = new MpegChunk(this, chunkh, _dstream);
      // I think only one MPEG chunk is allowed
      mpegChunkSeen = true;
    } else if ("cart".equals(id)) {
      if (cartChunkSeen) {
        dupChunkError(info, "Cart");
      }
      chunk = new CartChunk(this, chunkh, _dstream);
      cartChunkSeen = true;
    } else if ("bext".equals(id)) {
      if (broadcastExtChunkSeen) {
        dupChunkError(info, "Broadcast Audio Extension");
      }
      chunk = new BroadcastExtChunk(this, chunkh, _dstream);
      broadcastExtChunkSeen = true;
    } else if ("levl".equals(id)) {
      if (peakChunkSeen) {
        dupChunkError(info, "Peak Envelope");
      }
      chunk = new PeakEnvelopeChunk(this, chunkh, _dstream);
      peakChunkSeen = true;
    } else if ("link".equals(id)) {
      if (linkChunkSeen) {
        dupChunkError(info, "Link");
      }
      chunk = new LinkChunk(this, chunkh, _dstream);
      linkChunkSeen = true;
    } else if ("cue ".equals(id)) {
      if (cueChunkSeen) {
        dupChunkError(info, "Cue");
      }
      chunk = new CueChunk(this, chunkh, _dstream);
      cueChunkSeen = true;
    } else {
      info.setMessage(new InfoMessage("Chunk type '" + id + "' ignored", _nByte));
    }

    if (chunk != null) {
      if (!chunk.readChunk(info)) {
        return false;
      }
    } else {
      // Other chunk types are legal, just skip over them
      skipBytes(_dstream, chunkSize, this);
    }

    if ((chunkSize & 1) != 0) {
      // Must come out to an even byte boundary
      skipBytes(_dstream, 1, this);
      --bytesRemaining;
    }
    return true;
  }
예제 #2
0
 /* Factor out the reporting of duplicate chunks. */
 protected void dupChunkError(RepInfo info, String chunkName) {
   info.setMessage(new ErrorMessage("Multiple " + chunkName + " Chunks not permitted", _nByte));
   info.setValid(false);
 }
예제 #3
0
  /**
   * Parses the content of a purported WAVE digital object and stores the results in RepInfo.
   *
   * @param stream An InputStream, positioned at its beginning, which is generated from the object
   *     to be parsed
   * @param info A fresh RepInfo object which will be modified to reflect the results of the parsing
   * @param parseIndex Must be 0 in first call to <code>parse</code>. If <code>parse</code> returns
   *     a nonzero value, it must be called again with <code>parseIndex</code> equal to that return
   *     value.
   */
  public int parse(InputStream stream, RepInfo info, int parseIndex) throws IOException {
    initParse();
    info.setFormat(_format[0]);
    info.setMimeType(_mimeType[0]);
    info.setModule(this);

    _aesMetadata.setPrimaryIdentifier(info.getUri());
    if (info.getURLFlag()) {
      _aesMetadata.setOtherPrimaryIdentifierType("URI");
    } else {
      _aesMetadata.setPrimaryIdentifierType(AESAudioMetadata.FILE_NAME);
    }

    /* We may have already done the checksums while converting a
    temporary file. */
    _ckSummer = null;
    if (_je != null && _je.getChecksumFlag() && info.getChecksum().size() == 0) {
      _ckSummer = new Checksummer();
      _cstream = new ChecksumInputStream(stream, _ckSummer);
      _dstream = getBufferedDataStream(_cstream, _je != null ? _je.getBufferSize() : 0);
    } else {
      _dstream = getBufferedDataStream(stream, _je != null ? _je.getBufferSize() : 0);
    }

    try {
      // Check the start of the file for the right opening bytes
      for (int i = 0; i < 4; i++) {
        int ch = readUnsignedByte(_dstream, this);
        if (ch != sigByte[i]) {
          info.setMessage(new ErrorMessage("Document does not start with RIFF chunk", 0));
          info.setWellFormed(false);
          return 0;
        }
      }
      /* If we got this far, take note that the signature is OK. */
      info.setSigMatch(_name);

      // Get the length of the Form chunk.  This includes all
      // the subsequent chunks in the file, but excludes the
      // header ("FORM" and the length itself).
      bytesRemaining = readUnsignedInt(_dstream);

      // Read the file type.
      String typ = read4Chars(_dstream);
      bytesRemaining -= 4;
      if (!"WAVE".equals(typ)) {
        info.setMessage(new ErrorMessage("File type in RIFF header is not WAVE", _nByte));
        info.setWellFormed(false);
        return 0;
      }

      while (bytesRemaining > 0) {
        if (!readChunk(info)) {
          break;
        }
      }
    } catch (EOFException e) {
      info.setWellFormed(false);
      info.setMessage(new ErrorMessage("Unexpected end of file", _nByte));
      return 0;
    }

    // Set duration from number of samples and rate.
    if (numSamples > 0) {
      // _aesMetadata.setDuration((double) numSamples / sampleRate);
      _aesMetadata.setDuration(numSamples);
    }

    // Add note and label properties, if there's anything
    // to report.
    if (!_labels.isEmpty()) {
      _propList.add(new Property("Labels", PropertyType.PROPERTY, PropertyArity.LIST, _labels));
    }
    if (!_labeledText.isEmpty()) {
      _propList.add(
          new Property("LabeledText", PropertyType.PROPERTY, PropertyArity.LIST, _labeledText));
    }
    if (!_notes.isEmpty()) {
      _propList.add(new Property("Notes", PropertyType.PROPERTY, PropertyArity.LIST, _notes));
    }
    if (!_samples.isEmpty()) {
      _propList.add(new Property("Samples", PropertyType.PROPERTY, PropertyArity.LIST, _samples));
    }
    if (_exifInfo != null) {
      _propList.add(_exifInfo.buildProperty());
    }
    if (!formatChunkSeen) {
      info.setMessage(new ErrorMessage("No Format Chunk"));
      info.setWellFormed(false);
      return 0;
    }

    /* This file looks OK. */
    if (_ckSummer != null) {
      /* We may not have actually hit the end of file. If we're calculating
       * checksums on the fly, we have to read and discard whatever is
       * left, so it will get checksummed. */
      for (; ; ) {
        try {
          int n = skipBytes(_dstream, 2048, this);
          if (n == 0) {
            break;
          }
        } catch (Exception e) {
          break;
        }
      }
      info.setSize(_cstream.getNBytes());
      info.setChecksum(new Checksum(_ckSummer.getCRC32(), ChecksumType.CRC32));
      String value = _ckSummer.getMD5();
      if (value != null) {
        info.setChecksum(new Checksum(value, ChecksumType.MD5));
      }
      if ((value = _ckSummer.getSHA1()) != null) {
        info.setChecksum(new Checksum(value, ChecksumType.SHA1));
      }
    }

    info.setProperty(_metadata);

    // Indicate satisfied profiles.
    if (flagPCMWaveFormat) {
      info.setProfile("PCMWAVEFORMAT");
    }
    if (flagWaveFormatEx) {
      info.setProfile("WAVEFORMATEX");
    }
    if (flagWaveFormatExtensible) {
      info.setProfile("WAVEFORMATEXTENSIBLE");
    }
    if (flagBroadcastWave) {
      // Need to do some additional checks.
      if (!broadcastExtChunkSeen) {
        flagBroadcastWave = false;
      }
      if (compressionCode == FormatChunk.WAVE_FORMAT_MPEG) {
        if (!broadcastExtChunkSeen || !factChunkSeen) {
          flagBroadcastWave = false;
        }
      }
      if (flagBroadcastWave) {
        String prof = null;
        switch (broadcastVersion) {
          case 0:
            prof = "Broadcast Wave Version 0";
            break;

          case 1:
            prof = "Broadcast Wave Version 1";
            break;

            // Other versions are unknown at this time
        }
        if (prof != null) {
          info.setProfile(prof);
        }
      }
    }
    return 0;
  }