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:
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.