Autor
|
Tema: Buscar partes del archivo hex escrito en C# (Leído 13,316 veces)
|
Meta
|
Hola: Estaba pensando en hacer un programa con Windows Form, que lea archivos hex. Se puede abrir con este programa mismo llamado HxD. Por ejemplo, puedes ver en un archivo de una imagen esto pero solo pongo un trozo que es largo. Quiero hacer un programa en C#, al menos tener una idea de que al abrir y leer el archivo hex, busque en una dirección en concreta. Por ejemplo, la indicada abajo. En la dirección 7006, en el cual en hex tiene el valor 56 y en ASCII al lado es una letra mayúscula V. Si pulsas un botón en el formulario, en un textBox muestra dicho valor 56 y el otro textBox la letra V. Hasta ahí bien. Hay que hacer una especie de diccionario llenos de if, en el que si detecta el 56, en un tercer textBox muestre un mensaje, Español. Si detecta el 57, que muestre Italia, si es el 58 que muestre Portugal. Si en esos if hay otro valor que no esté incluido, que muestre en el tercer textBox, DESCONOCIDO. Hablando parece fácil. ¿Es muy complicado de hacer? Tampoco quiero pegarme media vida averiguar como se hace. Recuerdo que estamos hablando de un solo Byte, no de varios. Que si se puede, también me vale. Saludos.
|
|
|
En línea
|
|
|
|
Elektro Enjuto
|
¿Es muy complicado de hacer?
Tampoco quiero pegarme media vida averiguar como se hace.
Windows Forms: Windows Presentation Framework: Como podrás comprobar, el control de usuario del editor hexadecimal de WPF es mucho más completo y sofisticado que el control de usuario disponible para WinForms. Quizás lo quieras considerar como opción. El control de usuario "Be.HexEditor" para WinForms también parece tener una funcionalidad implementada para buscar un patrón de texto o bytes: PD: yo nunca la he llegado a usar, pero no debe ser difícil.
Supongo que con toda esta información será suficiente para resolver tus dudas, pero de todas formas aquí te dejo un algoritmo que he desarrollado en VB.NET para buscar un patrón de bytes en un objeto de tipo Stream (y derivados como FileStream, MemoryStream, etc): <HideModuleName> Public Module StreamExtensions ''' ---------------------------------------------------------------------------------------------------- ''' <summary> ''' Searches for the specified byte pattern within the source <see cref="Global.System.IO.Stream"/>, ''' and returns the zero-based index of the first occurrence. ''' </summary> ''' ---------------------------------------------------------------------------------------------------- ''' <param name="stream"> ''' The source <see cref="Global.System.IO.Stream"/>. ''' </param> ''' ''' <param name="startPosition"> ''' The zero-based starting position in the source <see cref="Global.System.IO.Stream"/> to perform the search. ''' </param> ''' ''' <param name="count"> ''' The number of bytes in the source <see cref="Global.System.IO.Stream"/> to search. ''' </param> ''' ---------------------------------------------------------------------------------------------------- ''' <returns> ''' The zero-based index of the first occurrence of the specified byte pattern ''' within the source <see cref="Global.System.IO.Stream"/>, ''' if found; otherwise, –1. ''' </returns> ''' ---------------------------------------------------------------------------------------------------- <Extension> <EditorBrowsable(EditorBrowsableState.Always)> <DebuggerStepThrough> Public Function IndexOf(stream As Global.System.IO.Stream, pattern As Byte(), startPosition As Long, count As Long) As Long Dim streamLength As Long = stream.Length Dim endPosition As Long = startPosition + count If startPosition > streamLength Then Throw New InvalidOperationException("Start Position is greater than the source stream length.", New ArgumentException("", paramName:=NameOf(startPosition))) End If If endPosition > streamLength Then Throw New InvalidOperationException("End Position is greater than the source stream length.", New ArgumentException("", paramName:=NameOf(count))) End If If count <= 0 Then Throw New ArgumentException("A value greater than zero is required.", paramName:=NameOf(count)) End If Dim initialStreamPosition As Long = stream.Position stream.Seek(startPosition, SeekOrigin.Begin) Dim foundPosition As Long Dim index As Integer Dim readByte As Integer While (stream.Position <= endPosition) readByte = stream.ReadByte() If readByte = -1 Then Exit While End If If pattern(index) <> readByte Then stream.Position -= index index = 0 Continue While End If If index = (pattern.Length - 1) Then foundPosition = stream.Position - index Exit While End If index += 1 End While stream.Seek(initialStreamPosition, SeekOrigin.Begin) Return foundPosition - 1 End Function <Extension> <EditorBrowsable(EditorBrowsableState.Always)> <DebuggerStepThrough> Public Function IndexOf(stream As Global.System.IO.Stream, pattern As Byte(), startPosition As Long) As Long Return StreamExtensions.IndexOf(stream, pattern, startPosition, stream.Length - startPosition) End Function End Module
Puedes convertirlo a C#. Mi algoritmo está basado en este otro escrito en C#: https://stackoverflow.com/a/76443727/1248295 - simplemente le he aportado más versatilidad de uso para poder limitar la búsqueda a una posición inicial y final, y le añadí control de errores. Nota: tanto ese algoritmo y el mio como el algoritmo de la respuesta de 'bruno conde' ( https://stackoverflow.com/questions/1471975/best-way-to-find-position-in-the-stream-where-given-byte-sequence-starts/1472689#1472689) no son ni por asomo tan rápidos para buscar un patrón de bytes en archivos de gran tamaño (ej. archivos de películas de varios GB) como lo es el algoritmo de búsqueda que utiliza el programa HxD. EDITO: El código anterior pero bastante mejor optimizado, con tiempos de búsqueda mucho más cortos sobre todo para buscar un patrón de bytes en un archivo de varios GB: <DebuggerStepThrough> <Extension> <EditorBrowsable(EditorBrowsableState.Always)> Public Function IndexOf(stream As Global.System.IO.Stream, pattern As Byte(), startPosition As Long, count As Long) As Long Dim streamLen As Long = stream.Length Dim pattLen As Integer = pattern.Length Dim endPos As Long = startPosition + count If startPosition > streamLen Then Throw New InvalidOperationException("Start Position is greater than the source stream length.", New ArgumentException("", paramName:=NameOf(startPosition))) End If If endPos > streamLen Then Throw New InvalidOperationException("End Position is greater than the source stream length.", New ArgumentException("", paramName:=NameOf(count))) End If If pattLen > (streamLen - startPosition) Then Throw New InvalidOperationException("Pattern Length is greater than the current search capacity length.", New ArgumentException("", paramName:=NameOf(count))) End If If count <= 0 Then Throw New ArgumentException("A value greater than zero is required.", paramName:=NameOf(count)) End If Dim matchPos As Long = -1 Dim pattPos As Integer = 0 Dim buffSize As Integer = CInt(Math.Min(4096, stream.Length)) Dim buff(buffSize - 1) As Byte Dim buffStream As New BufferedStream(stream, buffSize) buffStream.Seek(startPosition, SeekOrigin.Begin) Dim streamPos As Long = startPosition Dim readArray As Integer = -1 While (readArray <> 0) AndAlso (streamPos <= endPos) readArray = buffStream.Read(buff, 0, buffSize) For buffPos As Integer = 0 To buff.Length - 1 streamPos += 1 If buff(buffPos) <> pattern(pattPos) Then pattPos = 0 Else If pattPos = (pattLen - 1) Then matchPos = (streamPos - pattPos - 1) Exit While End If pattPos += 1 End If If streamPos > endPos Then Exit While End If Next End While Return matchPos End Function
Por cierto, en .NET Core directamente podrías utilizar la función MemoryExtensions.IndexOf: Saludos.
|
|
« Última modificación: 4 Septiembre 2023, 05:02 am por Elektro Enjuto »
|
En línea
|
@%$& #$ %&#$, ¡hay que decirlo más!.
|
|
|
Meta
|
Ni más información, voy a analizarlo. Muchas gracias honorable amigo.
|
|
|
En línea
|
|
|
|
Elektro Enjuto
|
No me aparece el botón para modificar mi post, creo que en el foro ahora hay un límite de tiempo o algo. En fin, era para corregir un pequeño despiste en el último código, por que la clase BufferedStream implementa la interface IDisposable, así que conviene llamar al método BufferedStream.Dispose para liberar los recursos.
También cabría mencionar que cuando se trata de procesar secuencialmente un FileStream para buscar un patrón de bytes, envolverlo en un objeto BufferedStream como hago en ese código aporta una mejoría de velocidad tremenda, pero por otro lado, cuando se trata de un MemoryStream es totalmente innecesario envolverlo en un objeto BufferedStream y hacerlo influye negativamente ralentizando la búsqueda del patrón de bytes, aunque la diferencia es muy diminuta (aproximadamente 2-3 segundos en mis pruebas) al buscar patrones de bytes que están posicionados casi al final en archivos de unos 2 GB, así que la diferencia es prácticamente imperceptible con búfers de mucho menos tamaño, pero bueno, ahí queda el dato por si se quieren llevar a cabo microoptimizaciones.
Saludos
|
|
« Última modificación: 6 Septiembre 2023, 23:43 pm por Elektro Enjuto »
|
En línea
|
@%$& #$ %&#$, ¡hay que decirlo más!.
|
|
|
Serapis
|
Si solo buscas un byte, la búsqueda puede ser secuencial (dentro de un for) y si buscas varios valores de bytes seguidos, tampoco es más complicado. Idioma Por cada byte en el array X Si bytes <=56) y (byte <=58) seleccionar caso byte caso 56: Idioma = "Español" caso 57: Idioma = caso 58: Idioma = "Italiano" fin casos salir de la funcion fin si siguiente Idioma = "Desconocido"
Si conoces un índice específico en el array donde se localiza, entonces el bucle for es innecesario. Si por el contrario debe buscarse en múltiples partes, otra función debe llamar a 'ésta', y entre sí deben retener el índice donde se localiza (por referencia), el bucle ya no vale un 'for each', ya deberá ser uno desde el índice hasta el final. Y siempre que se devuelva otro valor distinto de 'desconocido' implica que no se terminó de buscar en el array, luego la siguiente llamada continuará un índice más alto que donde se encontró. Cuando se devuelva 'desconocido', podrá leerse el siguiente tramo (caso de un fichero muy grande y no querer saturar la memoria con una lectura completa del fichero). Si el número de bytes a localizar es mayor de 1 y este valor pueda ser variable, entonces la eficiencia la encontrarás usando el algoritmo de Knuth, Morris y Pratt (KMP), o el de Boyer y Moore (BM)... (el de Karp Rabin puede ser más farragoso para cosas simples). Típicamente se utilizan para cadenas de texto, pero una cadena de texto no dejan de ser bytes consecutivos en el fichero. Eso sí, operando con números si ocupan más de 2 bytes ten en cuenta su 'endianidad'... pues altera el orden de ellos (caso que no ocupa cuando se trata de un texto). Hace años edité el artículo, era un galimatías probablemente producto de una traducción (de entonces) defectuosa del inglés, sin explicaciones ni detalles específicos: https://es.wikipedia.org/wiki/Algoritmo_Knuth-Morris-Pratt
|
|
« Última modificación: 28 Septiembre 2023, 13:52 pm por Serapis »
|
En línea
|
|
|
|
Meta
|
Muchas gracias camaradas, me toca practicar ya que estoy de vacaciones.
|
|
|
En línea
|
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
Leer partes de un archivo.
Programación Visual Basic
|
Scratz
|
6
|
2,940
|
26 Noviembre 2006, 19:40 pm
por Scratz
|
|
|
Borrar datos de un archivo escrito en php
PHP
|
Cerdo
|
0
|
1,981
|
28 Julio 2008, 05:48 am
por Cerdo
|
|
|
Como descargo un archivo de internet ( EN PARTES ). Alguien sabe?
« 1 2 »
.NET (C#, VB.NET, ASP)
|
70N1
|
17
|
10,239
|
29 Marzo 2010, 11:47 am
por 70N1
|
|
|
(Solucionado) Crear un archivo desde el menú contextual con contenido escrito?
Windows
|
Eleкtro
|
7
|
6,798
|
24 Diciembre 2012, 16:53 pm
por Eleкtro
|
|
|
Convertir manualmente partes de un archivo html a csv
Desarrollo Web
|
Esgrimidor
|
2
|
2,464
|
13 Septiembre 2017, 16:57 pm
por Esgrimidor
|
|