2025-12-15 00:51:18 +01:00
|
|
|
package fr.iutfbleu.sae.util;
|
|
|
|
|
|
2025-12-14 18:49:01 +01:00
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.OutputStream;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Décorateur de flux permettant l'écriture binaire à granularité du bit.
|
|
|
|
|
* <p>
|
|
|
|
|
* Cette classe encapsule un {@link OutputStream} existant et permet
|
|
|
|
|
* l'écriture de bits individuellement ou par groupes.
|
|
|
|
|
* Les bits sont accumulés afin de former des octets avant écriture.
|
|
|
|
|
* </p>
|
|
|
|
|
*
|
|
|
|
|
* <p>
|
|
|
|
|
* Utilisée notamment pour l'encodage des fichiers compressés
|
|
|
|
|
* (ex : format PIF utilisant des codes de Huffman).
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
|
|
|
|
public class BitOutputStream {
|
|
|
|
|
|
|
|
|
|
/** Flux de sortie sous-jacent */
|
|
|
|
|
private final OutputStream fluxSortie;
|
|
|
|
|
|
|
|
|
|
/** Octet en cours de construction */
|
|
|
|
|
private int octetEnConstruction;
|
|
|
|
|
|
|
|
|
|
/** Position du prochain bit à écrire (de 7 à 0) */
|
|
|
|
|
private int positionBit;
|
|
|
|
|
|
|
|
|
|
/** Indique si le flux est fermé */
|
|
|
|
|
private boolean fluxFerme;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Construit un écrivain binaire à partir d'un flux existant.
|
|
|
|
|
*
|
|
|
|
|
* @param fluxSortie flux de sortie à décorer
|
|
|
|
|
* @throws IllegalArgumentException si le flux est nul
|
|
|
|
|
*/
|
|
|
|
|
public BitOutputStream(OutputStream fluxSortie) {
|
|
|
|
|
if (fluxSortie == null) {
|
|
|
|
|
throw new IllegalArgumentException("Le flux de sortie ne peut pas être nul");
|
|
|
|
|
}
|
|
|
|
|
this.fluxSortie = fluxSortie;
|
|
|
|
|
this.octetEnConstruction = 0;
|
|
|
|
|
this.positionBit = 7;
|
|
|
|
|
this.fluxFerme = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Écrit un bit dans le flux binaire.
|
|
|
|
|
*
|
|
|
|
|
* @param bit bit à écrire (0 ou 1)
|
|
|
|
|
* @throws IOException si une erreur d'écriture survient
|
|
|
|
|
* @throws IllegalArgumentException si le bit n'est ni 0 ni 1
|
|
|
|
|
*/
|
|
|
|
|
public void writeBit(int bit) throws IOException {
|
|
|
|
|
if (bit != 0 && bit != 1) {
|
|
|
|
|
throw new IllegalArgumentException("Le bit doit être 0 ou 1");
|
|
|
|
|
}
|
|
|
|
|
if (fluxFerme) {
|
|
|
|
|
throw new IOException("Le flux de sortie est fermé");
|
|
|
|
|
}
|
|
|
|
|
if (bit == 1) {
|
|
|
|
|
this.octetEnConstruction = this.octetEnConstruction | (1 << this.positionBit);
|
|
|
|
|
}
|
|
|
|
|
this.positionBit--;
|
|
|
|
|
|
|
|
|
|
// si on atteint la fin de l'octet, on le grave dans le flux et rebolotte
|
|
|
|
|
if(this.positionBit < 0){
|
|
|
|
|
this.fluxSortie.write(this.octetEnConstruction);
|
|
|
|
|
this.octetEnConstruction = 0;
|
|
|
|
|
this.positionBit = 7;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Écrit une séquence de bits correspondant à une valeur entière.
|
|
|
|
|
*
|
|
|
|
|
* @param valeur valeur contenant les bits à écrire
|
|
|
|
|
* @param nombreBits nombre de bits à écrire (strictement positif)
|
|
|
|
|
* @throws IOException si une erreur d'écriture survient
|
|
|
|
|
*/
|
|
|
|
|
public void writeBits(int valeur, int nombreBits) throws IOException {
|
|
|
|
|
for (int i = nombreBits - 1; i >= 0; i--) {
|
|
|
|
|
int bit = (valeur >> i) & 1;
|
|
|
|
|
writeBit(bit);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Force l'écriture immédiate des données accumulées dans le flux sous-jacent.
|
|
|
|
|
*
|
|
|
|
|
* @throws IOException si une erreur survient lors du flush
|
|
|
|
|
*/
|
|
|
|
|
public void flush() throws IOException {
|
|
|
|
|
if (fluxFerme) {
|
|
|
|
|
throw new IOException("Le flux de sortie est fermé");
|
|
|
|
|
}
|
|
|
|
|
while (this.positionBit >= 0) {
|
|
|
|
|
writeBit(0);
|
|
|
|
|
}
|
|
|
|
|
this.fluxSortie.flush(); // Force l'écriture dans le flux sous-jacent
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Vide les buffers internes et ferme le flux de sortie.
|
|
|
|
|
*
|
|
|
|
|
* @throws IOException si une erreur survient lors de la fermeture
|
|
|
|
|
*/
|
|
|
|
|
public void fermerFlux() throws IOException {
|
|
|
|
|
// si le flux n'est pas déjà fermé
|
|
|
|
|
if (!fluxFerme) {
|
|
|
|
|
this.flush(); // compléter l'octet et forcer l'écriture
|
|
|
|
|
this.fluxSortie.close(); // fermer le flux sous-jacent
|
|
|
|
|
this.fluxFerme = true; // marquer le flux comme fermé
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|