Formato de archivo de canales del TV Samsung ue32h5303aw

El TV de Samsung modelo ue32h5303aw (y supongo que otros de la misma marca) puede exportar la lista de canales a un archivo llamado channel_list_UE32H5303_1401.scm en una unidad usb.

En cuanto al nombre de archivo, UE32H5303 representa el número de modelo y 1401 es la versión de lista de canales.

El archivo .scm es en realidad un ZIP que contiene los siguientes ficheros:

De estos, map-AirA contiene la lista de canales digitales terrestres, en el siguiente formato:

1000 registros de 320 bytes con los canales en el siguiente formato: (Puesto que uso basic, el primer byte es “byte 1”; usuarios de C o Java, restar 1 a cada registro):

Código VBA para leer un archivo map-AirD situado en el escritorio:

read_samsung_map_aird.bas
Sub Read_Samsung_map_AirD()
'
' Lee el fichero map_AirD extraído de un fichero de lista de canales de Samsung.
'
' (Para extraerlo, cambie la extensión del archivo SCM a ZIP y extráigalo).
'
 
Dim a$
Const outputDetails = 1     ' Detalles / Output channel details.
Const outputCSV = 2         ' CSV / Output a CSV channel list
Const outputHex = 4         ' Hex / Output hexdump
'
' Specify here what to output, like outputDetails + outputHex
' Indique aquí la salida que desea, como outputDetails+outputHex
'
Dim outputType As Integer: outputType = outputCSV
'
' Skip empty records? / ¿Saltar canales vacíos?
'
Dim skipEmpty As Boolean: skipEmpty = True
 
'
' Input file. This points to [user folder]\desktop\map-AirD
' Archivo de entrada. Esto apunta a escritorio\map-AirD
'
Dim inFile$: inFile$ = Environ$("userprofile") + "\Desktop\map-AirD"
'            inFile$=  "E:\prueba\map-AirD"
 
Dim f As Integer, g As Integer
Dim Position As Integer, Channel As Integer
 
 
Open inFile$ For Binary As #1
 
Seek 1, 1
While Loc(1) < LOF(1)
'
' El fichero contiene 1000 registros de 320 bytes, uno por cada posible canal.
' File contains 1000 320-byte records, one for each possible channel.
'
    a$ = InputB$(320, 1)
 
 
    If Not ((AscB(LeftB(a$, 1)) = 0) And (skipEmpty)) Then
        Position = AscB(MidB(a$, 1, 1))
        Channel = AscB(MidB(a$, 43, 1))
        pname$ = Trim$(MidB(a$, 66, 66 + 32))
        If AscB(MidB(a$, 22, 1)) = 255 Then
            ResolutionX = -1
        Else
            ResolutionX = AscB(MidB(a$, 21, 1)) + AscB(MidB(a$, 22, 1)) * 256
        End If
        If AscB(MidB(a$, 24, 1)) = 255 Then
            resolutionY = -1
        Else
            resolutionY = AscB(MidB(a$, 23, 1)) + AscB(MidB(a$, 24, 1)) * 256
        End If
        If AscB(MidB(a$, 4, 1)) = 255 Then
            VideoID = -1
            'RadioID: a PID that is valid for both TVs and radios, but is not the Audio ID
            RadioID = AscB(MidB(a$, 5, 1)) + AscB(MidB(a$, 6, 1)) * 256
        Else
            VideoID = AscB(MidB(a$, 3, 1)) + AscB(MidB(a$, 4, 1)) * 256
            'RadioID: a PID that is valid for both TVs and radios, but is not the Audio ID
            RadioID = AscB(MidB(a$, 5, 1)) + AscB(MidB(a$, 6, 1)) * 256
        End If
 
 
        'Display hex records for given channels only.
        ' This allows more detailed reverse engineering.
        '
        encontrar$ = ""
        If encontrar$ > "" Then
            If InStr(pname$, encontrar$) > 0 Then
                outputType = outputType Or outputHex
            Else
                outputType = outputType And (Not outputHex)
            End If
        End If
        '
        'pname$ is unicode, use Instr, Chr instead of InstrB, ChrB
        '
        inst = InStr(pname$, Chr(0))
        If inst > 0 Then pname$ = Left(pname$, inst - 1)
 
        ' No muestres canales vacíos
        ' Do not show empty channels
        If Position > 0 And Channel > 0 Then
 
            ' Salida para humanos
            ' Human readable output
            If (outputType And outputDetails) Then
                Debug.Print "Position #"; Position; ";";
                Debug.Print "Channel #"; Channel; ";";
                Debug.Print "Program name:"; pname$; ";";
                Debug.Print "AnchoBanda:"; AscB(MidB(a$, 13, 1));
                Debug.Print "VideoPID:"; VideoID;
                Debug.Print "_____PID:"; RadioID;
                Debug.Print "Resolution:"; ResolutionX; "x"; resolutionY
                'Debug.Print
            End If
 
            ''Salida para CSV / CSV output
            ' CSV formato es_ES: datos delimitados con ";"
            ' CSV es_ES format: data delimited with ";" instead of ","
            If (outputType And outputCSV) Then
                Debug.Print Trim$(Str$(Position)) + ";" + Trim(Str$(Channel)) + ";""" + pname$ + """";
                Debug.Print Str$(AscB(MidB(a$, 13, 1))) + ";";
                Debug.Print Str$(VideoID) + ";";
                Debug.Print Str$(RadioID) + ";";
                Debug.Print Str$(ResolutionX) + ";";
                Debug.Print Str$(resolutionY) + ";";
                Debug.Print
            End If
 
        End If
        xorval = 0
        xorval1 = 0
        xorval0 = 0
 
        For g = 0 To 319 Step 16
        '
        'Step 16: muestro 16 bytes en cada línea. / 16 bytes per line
        '
 
        'saltar registros vacíos en hexdump
        'skip empty records in hexdump
 
 
            For f = 1 To 16
                n = AscB(MidB$(a$, g + f, 1))
                xorval = xorval Xor n
                If (f And 1) Then xorval1 = xorval1 Xor n Else xorval0 = xorval0 Xor n
 
                If (outputType And outputHex) Then
                    Debug.Print Right$("00" + Hex$(n), 2) + " ";
                    If n >= 32 Then Debug.Print Chr$(n); Else Debug.Print (".");
                    Debug.Print " ";
                End If
            Next
            If (outputType And outputHex) Then Debug.Print
        Next
 
        'Last value is some form of verification code, maybe xor, maybe crc
        'Debug.Print GetCRC32(a$)
       '' Debug.Print Hex(xorval), Hex(xorval1), Hex(xorval0)
    End If
 
Wend
 
Close #1
Stop ' allows to use debug window before exiting
End Sub
Public Function GetCRC32(ByVal buffer As String) As String
    '
    ' Modified from code by Tim Hartwig,
    ' http://dotnet-snippets.com/snippet/calculate-crc32-hash-from-file/587
    '
        Dim CRC32Result As Long: CRC32Result = &HFFFFFFFF
        Dim CRC32Table(256) As Long
        Dim DWPolynomial As Long: DWPolynomial = &HEDB88320
        Dim DWCRC As Long
        Dim i As Integer, j As Integer, n As Integer
 
        'Create CRC32 Table
        For i = 0 To 255
            DWCRC = i
            For j = 8 To 1 Step -1
                If (DWCRC And 1) Then
                    DWCRC = ((DWCRC And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
                    DWCRC = DWCRC Xor DWPolynomial
                Else
                    DWCRC = ((DWCRC And &HFFFFFFFE) \ 2&) And &H7FFFFFFF
                End If
            Next j
            CRC32Table(i) = DWCRC
        Next i
 
        'Calcualting CRC32 Hash
 
            For i = 1 To LenB(buffer)
                n = (CRC32Result And &HFF) Xor AscB(MidB(buffer, i, 1))
                CRC32Result = ((CRC32Result And &HFFFFFF00) \ &H100) And &HFFFFFF
                CRC32Result = CRC32Result Xor CRC32Table(n)
            Next i
        GetCRC32 = Hex(Not (CRC32Result))
End Function

Otros archivos: * Cloneinfo contiene la línea “PSE” seguida por el número de modelo del televisor.