Erstmal vielen Dank an alle, die hier noch geantwortet haben, dachte nicht, dass ich noch so viel Hilfe bekomme
Auf Basis des Beitrags von Der_Unwissende hab ich mir mal was zurecht gebastelt, wäre nett wenn ihr mal drüber gucken könntet, vielleicht fällt euch noch was auf, was man anders/besser machen könnte, aber funktionieren tut es perfekt!
Um nicht die ganze Datei Byte für Byte nach einem "INFO" zu durchsuchen, hab ich einfach mal beim Dateiende minus einer Konstanten angefangen zu suchen, die Konstante erhält die in etwa maximale Größe des INFO List Chunks:
Delphi-Quellcode:
const
MAX_LISTCHUNK_SIZE = 100000;
{ INFO List Chunk von einer Datei einlesen: die ChunkID und die einsprechende Beschreibung dazu werden in übergebenen TStrings gespeichert }
function ReadINFOListChunk(const FileName: string; var ChunkID, Description: TStrings): Boolean;
var Stream: TStream; i: Integer; s: array[0..3] of Char; sl: array[0..255] of Char;
begin
s := #0#0#0#0;
Result := False;
Stream := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite);
try
Stream.Seek(-MAX_LISTCHUNK_SIZE, soFromEnd);
// bis zu 'INFO' einlesen
while Stream.Read(s, 1) = 1 do
if s[0] = 'I' then
begin
if Stream.Read(s, 3) = 3 then
begin
if (s = 'NFO') then Break
else Stream.Seek(-3, soFromCurrent);
end
else Exit;
end;
if s <> 'NFO' then Exit;
// INFO Chunk einlesen
Result := True;
while Stream.Read(s, 4) = 4 do
begin
ChunkID.Append(s); // Chunk ID
if Stream.Read(i, 4) = 4 then
begin
if Stream.Read(sl, i) = i then
Description.Append(sl) // Description
else Exit;
end
else Exit;
// Null-Bytes überspringen
while (Stream.Read(s, 1) = 1) and (s[0] = #0) do
begin end;
Stream.Seek(-1, soFromCurrent);
end;
finally
FreeAndNil(Stream);
end;
end;
{ INFO List Chunk in eine Datei schreiben: die ChunkID und die einsprechende Beschreibung werden in TStrings übergebenen }
procedure WriteINFOListChunk(const FileName: string; const ChunkID, Description: TStrings);
var Stream: TStream; i, j: Integer;
begin
// INFO List Chunk löschen, falls vorhanden
RemoveINFOListChunk(FileName);
Stream := TFileStream.Create(FileName, fmOpenReadWrite, fmShareDenyWrite);
try
Stream.Seek(0, soFromEnd);
// Header schreiben
Stream.Write('LIST:'+#0#0#0+'INFO', 12);
for i := 0 to ChunkID.Count - 1 do
begin
Stream.Write(PChar(ChunkID[i])^, 4); // Chunk ID
j := Length(Description[i]) + 1;
Stream.Write(j, 4); // Länge
Stream.Write(PChar(Description[i] + #0)^, j); // Description
end;
finally
FreeAndNil(Stream);
end;
end;
{ INFO List Chunk von einer Datei löschen }
function RemoveINFOListChunk(const FileName: string): Boolean;
var Stream: TStream; s: array[0..3] of Char;
begin
s := #0#0#0#0;
Result := False;
Stream := TFileStream.Create(FileName, fmOpenReadWrite, fmShareDenyWrite);
try
Stream.Seek(-MAX_LISTCHUNK_SIZE, soFromEnd);
// bis zu 'INFO' einlesen
while Stream.Read(s, 1) = 1 do
if s[0] = 'I' then
begin
if Stream.Read(s, 3) = 3 then
begin
if (s = 'NFO') then Break
else Stream.Seek(-3, soFromCurrent);
end
else Exit;
end;
if s <> 'NFO' then Exit;
Stream.Seek(-12, soFromCurrent);
// List Chunk enthält nur INFO -> kompletten List Chunk löschen
if (Stream.Read(s, 4) = 4) and (s = 'LIST') then
Stream.Size := Stream.Position - 4
else
Stream.Size := Stream.Position + 4;
Result := True;
finally
FreeAndNil(Stream);
end;
end;
Ach ja, eine ausführliche Erklärung zu den einzelnen Chunk ID's lässt sich
hier finden, unter dem Absatz "INFO List Chunk".
Hier noch Beispiele zur Anwendung:
Delphi-Quellcode:
procedure TForm1.ButtonReadClick(Sender: TObject);
var ChunkID, Description: TStrings; i: Integer; s: String;
begin
ChunkID := TStringList.Create;
Description := TStringList.Create;
try
if ReadINFOListChunk('C:\test.wav', ChunkID, Description) then
begin
s := '';
for i := 0 to ChunkID.Count - 1 do
s := s + ChunkID[i] +#9+ Description[i] +#13#10;
ShowMessage('Datei "C:\test.wav" enthält folgenden INFO List Chunk:' +#13#10#13#10+ s);
end
else
ShowMessage('Datei "C:\test.wav" enthält keinen INFO List Chunk.');
finally
ChunkID.Free;
Description.Free;
end;
end;
procedure TForm1.ButtonWriteClick(Sender: TObject);
var ChunkID, Description: TStrings;
begin
ChunkID := TStringList.Create;
Description := TStringList.Create;
try
ChunkID.Add('IART');
Description.Add('Interpret');
ChunkID.Add('INAM');
Description.Add('Titel');
WriteINFOListChunk('C:\test.wav', ChunkID, Description);
finally
ChunkID.Free;
Description.Free;
end;
end;
procedure TForm1.ButtonRemoveClick(Sender: TObject);
begin
if RemoveINFOListChunk('C:\test.wav') then
ShowMessage('INFO List Chunk wurde gelöscht.')
else
ShowMessage('Kein INFO List Chunk vorhanden.');
end;
Im Anhang noch der Code als
Unit: