For example I want to read a WAVE file with a unicode program and use a structure for the chunk headers like this.
Code: Select all
Structure headerStruc
type.s{4} ;must be 4 byte but is 8 in unicode
size.l
EndStructure
Code: Select all
Structure headerStruc
type.s{4} ;must be 4 byte but is 8 in unicode
size.l
EndStructure
Code: Select all
Structure headerStruc
type.a[4]
size.l
EndStructure
Define Test.headerStruc
PokeS(@Test\type, "ABCD", 4, #PB_Ascii | #PB_String_NoZero)
Debug PeekS(@Test\type, 4, #PB_Ascii)
Starting with 5.50 strings in PB are stored in as UNICODE strings with UCS2 encoding (on windows, I did not found any information about the encoding on Linux or MacOS).djes wrote:In nco2k's code, there's not only a structure, but a code to read/decode ASCII. Apart of this, a structure is a good way to handle file headers.
Code: Select all
Structure tID
StructureUnion
char.a[4]
lID.l
EndStructureUnion
EndStructure
Global id.tID, i
Structure tHeader
chunkID.tID
size.l
EndStructure
Macro CreateIDFromChars( a, b, c, d )
d << 24 + c << 16 + b << 8 + a
EndMacro
#ID_Chunk_RIFF = CreateIDFromChars( 'R', 'I', 'F', 'F' )
id\lID = #ID_Chunk_RIFF
Debug "Single letters of ID:"
For i = 0 To 3
Debug " --> Letter " + Str(i+1) + ": " + Chr(id\char[i])
Next i
Debug "ID read as 4 byte ASCII string: " + PeekS(@id, 4, #PB_Ascii)
Debug "ID as hexadecimal long value: $" + Hex(id\lID)
Debug "ID as deczimal long value: " + Str(id\lID)
Debug "----"
Procedure CreateIDFromString(IdString.s)
Protected LongID.l
If Len(IdString) = 4
PokeS(@LongID, IdString, 4, #PB_Ascii | #PB_String_NoZero)
EndIf
ProcedureReturn LongID
EndProcedure
id\lID = CreateIDFromString("WAVE")
Debug "Single letters of ID:"
For i = 0 To 3
Debug " --> Letter " + Str(i+1) + ": " + Chr(id\char[i])
Next i
Debug "ID read as 4 byte ASCII string: " + PeekS(@id, 4, #PB_Ascii)
Debug "ID as hexadecimal long value: $" + Hex(id\lID)
Debug "ID as deczimal long value: " + Str(id\lID)
Code: Select all
Structure tHeader
chunkID.l
size.l
EndStructure
Global header.tHeader
Procedure CreateIDFromString(IdString.s)
Protected LongID.l
If Len(IdString) = 4
PokeS(@LongID, IdString, 4, #PB_Ascii | #PB_String_NoZero)
EndIf
ProcedureReturn LongID
EndProcedure
Procedure.s GetIDstring(ID.l)
ProcedureReturn PeekS(@ID, 4, #PB_Ascii)
EndProcedure
header\chunkID = CreateIDFromString("RIFF")
Debug "ID read as 4 byte ASCII string: '" + GetIDstring(header\chunkID) + "'"
Debug "ID as hexadecimal long value: $" + Hex(header\chunkID)
Debug "ID as deczimal long value: " + Str(header\chunkID)
Debug "----"
Global otherID.l
otherID = CreateIDFromString("WAVE")
Debug "ID read as 4 byte ASCII string: '" + GetIDstring(otherID) + "'"
Debug "ID as hexadecimal long value: $" + Hex(otherID)
Debug "ID as deczimal long value: " + Str(otherID)
Debug "----"
otherID = CreateIDFromString("fmt ")
Debug "ID read as 4 byte ASCII string: '" + GetIDstring(otherID) + "'"
Debug "ID as hexadecimal long value: $" + Hex(otherID)
Debug "ID as deczimal long value: " + Str(otherID)
Debug "----"
otherID = CreateIDFromString("data")
Debug "ID read as 4 byte ASCII string: '" + GetIDstring(otherID) + "'"
Debug "ID as hexadecimal long value: $" + Hex(otherID)
Debug "ID as deczimal long value: " + Str(otherID)
Debug "----"
Code: Select all
Structure tHeader
chunkID.l
size.l
EndStructure
Global header.tHeader
;compare a pointer to the start of a chunk with ID strings in DataSection, first index starts at 1
Procedure CheckIDstring(*header.tHeader, index = -1)
Protected indexMax = ((?EndChunkIDstrings - ?ChunkIDstrings) / SizeOf(Long)) + 1
If index >= 1 And index < indexMax
If CompareMemory(*header, ?ChunkIDStrings + SizeOf(Long) * (index - 1), SizeOf(Long))
ProcedureReturn index
EndIf
Else
For index = 1 To indexMax
If CompareMemory(*header, ?ChunkIDStrings + SizeOf(Long) * (index - 1), SizeOf(Long))
ProcedureReturn index
EndIf
Next
EndIf
ProcedureReturn 0 ; no match
EndProcedure
;returns ChunkIDstring as Unicode string
Procedure.s displayChunkIDstring(index)
ProcedureReturn PeekS(?ChunkIDStrings + SizeOf(Long) * (index - 1), SizeOf(Long), #PB_Ascii)
EndProcedure
;returns ChunkIDstring as a string of bytes for display
Procedure.s displayChunkIDstringAsBytes(*header.tHeader)
Protected i, output.s
For i = 0 To 3
output + "$" + Hex(PeekA(*header + i), #PB_Byte) + " "
Next
ProcedureReturn RTrim(output, " ")
EndProcedure
;test data to identify chunk ID String
#testdataByteLength = 12
Define *buffer, i, result
*buffer = AllocateMemory(#testdataByteLength * 2) ;make it bigger than needed
Restore SampleDataFromFile
If *buffer
For i = 0 To 2
CopyMemory(?SampleDataFromFile + i * #testdataByteLength, *buffer, #testdataByteLength)
result = CheckIDstring(*buffer)
If result > 1
Debug "DataSample " + i + " has chunkIDstring " + result + ": '" + displayChunkIDstring(result)
Else
Debug "DataSample had an unknown chunkIDstring: " + displayChunkIDstringAsBytes(*buffer)
EndIf
Next
EndIf
DataSection
ChunkIDstrings:
Data.a 'R', 'I', 'F', 'F'
Data.a 'W', 'A', 'V', 'E'
Data.a 'f', 'm', 't', ' '
Data.a 'd', 'a', 't', 'a'
EndChunkIDstrings:
SampleDataFromFile:
Data.a $52, $49, $46, $46, $24, $08, $00, $00, $57, $41, $56, $45
Data.a $66, $6d, $74, $20, $10, $00, $00, $00, $01, $00, $02, $00; the rest of this chunk $22, $56, $00, $00, $88, $58, $01, $00, $04, $00, $10, $00
Data.a $64, $61, $74, $61, $00, $08, $00, $00, $00, $00, $00, $00; the rest of this chunk $24, $17, $1e, $f3, $3c, $13, $3c, $14, $16, $f9, $18, $f9, $34, $e7, $23, $a6, $3c, $f2, $24, $f2, $11, $ce, $1a, $0d
Data.a $62, $65, $65, $66, $24, $08, $00, $00, $57, $41, $56, $45
EndDataSection
Code: Select all
#WAVE = $45564157 ;"WAVE"
#RIFF = $46464952 ;"RIFF"
Structure headerStruc
type.l
size.l
EndStructure
*h.headerStruc
If *h\type = #WAVE
;do something...
ElseIf *h\type = #RIFF
;do something...
EndIf
Code: Select all
Procedure.s asci2Long(*buffer)
;//*buffer is the address of a string like @"WAVE" or @"'lpcm'"
Dim output.a(4)
*byte.character
*byte = *buffer
*comment.string
*comment = @*buffer
If *byte\c = 39
*byte = *buffer + SizeOf(character)
i =3
While i >=0
output(i) = *byte\c
i -1
*byte +SizeOf(character)
Wend
ProcedureReturn "$" +Hex(PeekL(@output() ) , #PB_Long )+" ;" +*comment\s
Else
While i < 4
output(i) = *byte\c
i +1
*byte +SizeOf(character)
Wend
ProcedureReturn "$" +Hex(PeekL(@output() ) , #PB_Long )+" ;" +Chr(34) +*comment\s +Chr(34)
EndIf
EndProcedure