diff --git a/Ghidra/Framework/SoftwareModeling/data/softwaremodeling.theme.properties b/Ghidra/Framework/SoftwareModeling/data/softwaremodeling.theme.properties index be5955e97d..9c1b524ff2 100644 --- a/Ghidra/Framework/SoftwareModeling/data/softwaremodeling.theme.properties +++ b/Ghidra/Framework/SoftwareModeling/data/softwaremodeling.theme.properties @@ -4,9 +4,7 @@ icon.content.handler.archive.dt = closedBookBlue.png icon.content.handler.program = program_obj.png -icon.data.type.aiff = audio-volume-medium.png -icon.data.type.au = audio-volume-medium.png -icon.data.type.wave = audio-volume-medium.png +icon.data.type.audio.player = audio-volume-medium.png [Dark Defaults] diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AIFFDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AIFFDataType.java index 38db4e5796..586bca85c3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AIFFDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AIFFDataType.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,14 +15,6 @@ */ package ghidra.program.model.data; -import java.awt.event.MouseEvent; -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import javax.sound.sampled.*; -import javax.swing.Icon; - -import generic.theme.GIcon; import ghidra.docking.settings.Settings; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemoryAccessException; @@ -104,36 +96,6 @@ public class AIFFDataType extends BuiltIn implements Dynamic { return ""; } - private static class AIFFData implements Playable { - - private static final Icon AUDIO_ICON = new GIcon("icon.data.type.aiff"); - private byte[] bytes; - - public AIFFData(byte[] bytes) { - this.bytes = bytes; - } - - @Override - public void clicked(MouseEvent event) { - - try { - Clip clip = AudioSystem.getClip(); - AudioInputStream ais = - AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes)); - clip.open(ais); - clip.start(); - } - catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) { - Msg.debug(this, "Unable to play audio", e); - } - } - - @Override - public Icon getImageIcon() { - return AUDIO_ICON; - } - } - @Override public Object getValue(MemBuffer buf, Settings settings, int length) { byte[] data = new byte[length]; @@ -141,12 +103,12 @@ public class AIFFDataType extends BuiltIn implements Dynamic { Msg.error(this, "AIFF-Sound error: Not enough bytes in memory"); return null; } - return new AIFFData(data); + return new AudioPlayer(data); } @Override public Class getValueClass(Settings settings) { - return AIFFData.class; + return AudioPlayer.class; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AUDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AUDataType.java index 7ba4b6c5b1..d02df66117 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AUDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AUDataType.java @@ -15,14 +15,6 @@ */ package ghidra.program.model.data; -import java.awt.event.MouseEvent; -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import javax.sound.sampled.*; -import javax.swing.Icon; - -import generic.theme.GIcon; import ghidra.docking.settings.Settings; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemoryAccessException; @@ -56,7 +48,7 @@ public class AUDataType extends BuiltIn implements Dynamic { Msg.debug(this, "Invalid AU magic number"); return -1; } - //Ints always stored as big endian in this format but can be in any kind of program so must get the ints as big endian even when in a little endian program + //Ints always stored as big endian in this format but can be in any kind of program so must get the ints as big endian even when in a little endian program int dataOffset = GhidraBigEndianDataConverter.INSTANCE.getInt(buf, 4); int dataSize = GhidraBigEndianDataConverter.INSTANCE.getInt(buf, 8); @@ -108,36 +100,6 @@ public class AUDataType extends BuiltIn implements Dynamic { return ""; } - private static class AUData implements Playable { - - private static final Icon AUDIO_ICON = new GIcon("icon.data.type.au"); - private byte[] bytes; - - public AUData(byte[] bytes) { - this.bytes = bytes; - } - - @Override - public void clicked(MouseEvent event) { - - try { - Clip clip = AudioSystem.getClip(); - AudioInputStream ais = - AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes)); - clip.open(ais); - clip.start(); - } - catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) { - Msg.debug(this, "Unable to play audio", e); - } - } - - @Override - public Icon getImageIcon() { - return AUDIO_ICON; - } - } - @Override public Object getValue(MemBuffer buf, Settings settings, int length) { byte[] data = new byte[length]; @@ -145,12 +107,12 @@ public class AUDataType extends BuiltIn implements Dynamic { Msg.error(this, "AU-DataTpe Error: Not enough bytes in memory"); return null; } - return new AUData(data); + return new AudioPlayer(data); } @Override public Class getValueClass(Settings settings) { - return AUData.class; + return AudioPlayer.class; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AudioPlayer.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AudioPlayer.java new file mode 100644 index 0000000000..3c1e0a8bea --- /dev/null +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/AudioPlayer.java @@ -0,0 +1,71 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.program.model.data; + +import java.awt.event.MouseEvent; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import javax.sound.sampled.*; +import javax.sound.sampled.LineEvent.Type; +import javax.swing.Icon; + +import generic.theme.GIcon; +import ghidra.util.Msg; + +public class AudioPlayer implements Playable, LineListener { + + private static final Icon AUDIO_ICON = new GIcon("icon.data.type.audio.player"); + + private byte[] bytes; + + public AudioPlayer(byte[] bytes) { + this.bytes = bytes; + } + + @Override + public Icon getImageIcon() { + return AUDIO_ICON; + } + + @Override + public void clicked(MouseEvent event) { + try (AudioInputStream stream = + AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes))) { + Clip clip = AudioSystem.getClip(); + clip.addLineListener(this); + clip.open(stream); + clip.start(); + } + catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) { + Msg.debug(this, "Unable to play audio", e); + } + } + + @Override + public void update(LineEvent event) { + LineEvent.Type eventType = event.getType(); + + if (eventType != Type.STOP && eventType != Type.CLOSE) { + return; + } + + if (event.getSource() instanceof Clip clip) { + clip.removeLineListener(this); + clip.close(); + } + } +} diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WAVEDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WAVEDataType.java index 4a6197f9fd..632048327f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WAVEDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/WAVEDataType.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,14 +15,6 @@ */ package ghidra.program.model.data; -import java.awt.event.MouseEvent; -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import javax.sound.sampled.*; -import javax.swing.Icon; - -import generic.theme.GIcon; import ghidra.docking.settings.Settings; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.mem.MemoryAccessException; @@ -101,36 +93,6 @@ public class WAVEDataType extends BuiltIn implements Dynamic { return ""; } - private static class WAVEData implements Playable { - - private static final Icon AUDIO_ICON = new GIcon("icon.data.type.wave"); - private byte[] bytes; - - public WAVEData(byte[] bytes) { - this.bytes = bytes; - } - - @Override - public void clicked(MouseEvent event) { - - try { - Clip clip = AudioSystem.getClip(); - AudioInputStream ais = - AudioSystem.getAudioInputStream(new ByteArrayInputStream(bytes)); - clip.open(ais); - clip.start(); - } - catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) { - Msg.debug(this, "Unable to play audio", e); - } - } - - @Override - public Icon getImageIcon() { - return AUDIO_ICON; - } - } - @Override public Object getValue(MemBuffer buf, Settings settings, int length) { byte[] data = new byte[length]; @@ -138,13 +100,12 @@ public class WAVEDataType extends BuiltIn implements Dynamic { Msg.error(this, "WAVE-Sound error: " + "Not enough bytes!"); return null; } - WAVEData waveData = new WAVEData(data); - return waveData; + return new AudioPlayer(data); } @Override public Class getValueClass(Settings settings) { - return WAVEData.class; + return AudioPlayer.class; } @Override