2010-04-28 21 views
16

Por favor tengan paciencia conmigo ya que me han lanzado a la mitad de este proyecto sin conocer todos los antecedentes. Si tienes preguntas sobre la WTF, créeme, yo también las tengo.¿Cómo detectar si un archivo es PDF o TIFF?

Aquí está el escenario: Tengo un montón de archivos que residen en un servidor IIS. No tienen extensión de archivo en ellos. Solo archivos desnudos con nombres como "asda-2342-sd3rs-asd24-ut57" y así sucesivamente. Nada intuitivo.

El problema es que necesito servir archivos en una página ASP.NET (2.0) y visualizar los archivos tiff como tiff y los archivos PDF como PDF. Lamentablemente, no sé cuál es cuál y necesito poder mostrarlos adecuadamente en sus respectivos formatos.

Por ejemplo, digamos que hay 2 archivos que necesito mostrar, uno es tiff y el otro es PDF. La página debe mostrarse con una imagen tiff, y quizás un enlace que abra el PDF en una nueva pestaña/ventana.

El problema:

Como estos archivos son todos extensión menor que tuve que forzar IIS para servir sólo como todo lo TIFF. Pero si hago esto, los archivos PDF no se mostrarán. Podría cambiar IIS para obligar al tipo MIME a ser PDF para extensiones de archivo desconocidas, pero tendría el problema inverso.

http://support.microsoft.com/kb/326965

Es éste un problema más fácil de lo que pienso o es tan desagradable como que estoy esperando?

Respuesta

19

, la gente lo suficiente OK están recibiendo este mal que voy a publicar algunos código que tengo para identificar archivos TIFF:

private const int kTiffTagLength = 12; 
private const int kHeaderSize = 2; 
private const int kMinimumTiffSize = 8; 
private const byte kIntelMark = 0x49; 
private const byte kMotorolaMark = 0x4d; 
private const ushort kTiffMagicNumber = 42; 


private bool IsTiff(Stream stm) 
{ 
    stm.Seek(0); 
    if (stm.Length < kMinimumTiffSize) 
     return false; 
    byte[] header = new byte[kHeaderSize]; 

    stm.Read(header, 0, header.Length); 

    if (header[0] != header[1] || (header[0] != kIntelMark && header[0] != kMotorolaMark)) 
     return false; 
    bool isIntel = header[0] == kIntelMark; 

    ushort magicNumber = ReadShort(stm, isIntel); 
    if (magicNumber != kTiffMagicNumber) 
     return false; 
    return true; 
} 

private ushort ReadShort(Stream stm, bool isIntel) 
{ 
    byte[] b = new byte[2]; 
    _stm.Read(b, 0, b.Length); 
    return ToShort(_isIntel, b[0], b[1]); 
} 

private static ushort ToShort(bool isIntel, byte b0, byte b1) 
{ 
    if (isIntel) 
    { 
     return (ushort)(((int)b1 << 8) | (int)b0); 
    } 
    else 
    { 
     return (ushort)(((int)b0 << 8) | (int)b1); 
    } 
} 

Pirateé además un código mucho más general para conseguir esto.

Para PDF, que tienen código que se parece a esto:

public bool IsPdf(Stream stm) 
{ 
    stm.Seek(0, SeekOrigin.Begin); 
    PdfToken token; 
    while ((token = GetToken(stm)) != null) 
    { 
     if (token.TokenType == MLPdfTokenType.Comment) 
     { 
      if (token.Text.StartsWith("%PDF-1.")) 
       return true; 
     } 
     if (stm.Position > 1024) 
      break; 
    } 
    return false; 
} 

Ahora, GetToken() es una llamada a un escáner que tokenizes una corriente en tokens PDF. Esto no es trivial, así que no voy a pegarlo aquí. Estoy usando el tokenizer en vez de mirar subcadena para evitar un problema como este:

% the following is a PostScript file, NOT a PDF file 
% you'll note that in our previous version, it started with %PDF-1.3, 
% incorrectly marking it as a PDF 
% 
clippath stroke showpage 

este código se marca como un PDF NO por el fragmento de código anterior, mientras que un trozo más simplista de código de forma incorrecta marcarlo como PDF

Debo señalar también que la especificación ISO actual carece de las notas de implementación que estaban en la especificación anterior propiedad de Adobe. Lo más importante de la Referencia PDF, versión 1.6:

Acrobat viewers require only that the header appear somewhere within 
the first 1024 bytes of the file. 
+0

gracias! Voy a comprobar esto esta noche – eviljack

+0

impresionante, funciona! – eviljack

+0

stm.Seek (0); falla para mí, no compila Estoy usando vs 2008, .net 3.5. – Kiquenet

0

Si ve here, verá que el TIFF generalmente comienza con "números mágicos" 0x49 0x49 0x2A 0x00 (también se dan algunas otras definiciones), que son los primeros 4 bytes del archivo.

Tan solo utilice estos primeros 4 bytes para determinar si el archivo es TIFF o no.

EDITAR, probablemente sea mejor hacerlo de otra manera, y primero detecte el PDF. Los números mágicos para PDF están más estandarizados: como señaló amablemente Plinth, comienzan con "% PDF" en algún lugar de los primeros 1024 bytes (0x25 0x50 0x44 0x46). source

+0

estos números mágicos dependen de little/big endian. – Andrey

+1

Esto está cerca, pero está mal. Un TIFF comienza con una de las dos firmas, 0x49 0x49 0x2a 0x00 O 0x4d 0x4d 0x00 0x2a. – plinth

+0

Su verificación de PDF también es incorrecta. El% PDF solo debe aparecer en los primeros 1024 bytes. – plinth

8

TIFF puede ser detectado por mira a escondidas en primera bytes http://local.wasp.uwa.edu.au/~pbourke/dataformats/tiff/

Los primeros 8 bytes forma la cabecera. Los primeros dos bytes de los cuales es "II" para el pedido de bytes little endian o "MM" para el pedido de bytes de big endian.

Sobre PDF: http://www.adobe.com/devnet/livecycle/articles/lc_pdf_overview_format.pdf

La cabecera contiene una sola línea que identifica la versión de PDF. Ejemplo:% PDF-1.6

+0

El documento de Adobe no es exactamente la especificación exacta. % PDF-1.x, donde x es un número puede aparecer en cualquier lugar dentro de los primeros 1K del archivo. – plinth

+0

bien, aquí está la especificación más completa http://www.adobe.com/devnet/acrobat/pdfs/pdf_reference_1-7.pdf es> 30 Mb – Andrey

2

Internamente, la información del encabezado del archivo debería ayudar. si abre un archivo de bajo nivel, como StreamReader() o FOPEN(), observe los dos primeros caracteres del archivo ... Casi todos los tipos de archivo tienen su propia firma.

PDF always starts with "%P" (but more specifically would have like %PDF) 
TIFF appears to start with "II" 
Bitmap files with "BM" 
Executable files with "MZ" 

que he tenido que hacer frente a esto en el pasado también ... también para ayudar a prevenir los archivos no deseados de ser subido a un sitio determinado e inmediatamente abortar una vez verificado.

EDIT - Publicado código de ejemplo para leer y archivo de prueba tipos de cabecera

String fn = "Example.pdf"; 

StreamReader sr = new StreamReader(fn); 
char[] buf = new char[5]; 
sr.Read(buf, 0, 4); 
sr.Close(); 
String Hdr = buf[0].ToString() 
    + buf[1].ToString() 
    + buf[2].ToString() 
    + buf[3].ToString() 
    + buf[4].ToString(); 

String WhatType; 
if (Hdr.StartsWith("%PDF")) 
    WhatType = "PDF"; 
else if (Hdr.StartsWith("MZ")) 
    WhatType = "EXE or DLL"; 
else if (Hdr.StartsWith("BM")) 
    WhatType = "BMP"; 
else if (Hdr.StartsWith("?_")) 
    WhatType = "HLP (help file)"; 
else if (Hdr.StartsWith("\0\0\1")) 
    WhatType = "Icon (.ico)"; 
else if (Hdr.StartsWith("\0\0\2")) 
    WhatType = "Cursor (.cur)"; 
else 
    WhatType = "Unknown"; 
+0

mr.DRapp, ¿algún código de muestra? – Kiquenet

+0

@alhambraeidos - Publiqué el código actualizado a través de la muestra de C# – DRapp

+0

¡No debería estar escribiendo "parece comenzar con" en la parte crítica de la respuesta! Según la especificación, los archivos TIFF comienzan con 2 bytes de ASCII "II" o "MM", seguidos de 2 bytes en (II) Intel little-endian o (MM) Pedido de bytes Motorola big-endian, formando el entero 42. – Spike0xff

0

Usted va a tener que escribir un ashx para obtener el archivo solicitado.

luego, su manejador debe leer los primeros bytes (más o menos) para determinar cuál es realmente el tipo de archivo-- PDF y TIFF tienen "números mágicos" al principio del archivo que puede usar para determinar esto, luego configura tus Encabezados de respuesta en consecuencia.

4

lectura de la memoria para cada formato de archivo le dirá cómo identificar los archivos de ese formato.

TIFF archivos - Comprobar bytes 1 y 2 para 0x4D4D o 0x4949 y bytes 2-3 para el valor '42'.

Página 13 de la especificación lee:

archivo

Un TIFF comienza con una cabecera de 8 bytes del archivo de imagen , que contiene la siguiente información : Bytes 0-1: El orden de bytes usada dentro del archivo . Los valores legales son: "II" (4949.H) "MM" (4D4D.H) En el formato "II", byte el orden es siempre desde el mínimo byte significativo hasta el máximo byte significativo, para ambos 16 -bit y enteros de 32 bits Se llama orden de bytes little-endian. En el formato "MM" , el orden de bytes siempre es desde la mayoría significativo a menos significativo, para enteros de 16 bits y 32 bits. Este se llama orden de bytes big-endian. Bytes 2-3 Un número arbitrario pero cuidadosamente seleccionado (42) que identifica adicionalmente el archivo como un archivo TIFF. El orden byte depende del valor de Bytes 0-1.

PDF Los archivos comienzan con la versión en PDF seguida de varios bytes binarios. (Creo que ahora tienen que comprar la especificación ISO para la versión actual.)

Sección 7.5.2

La primera línea de un archivo PDF será una cabecera que consta de los 5 caracteres % PDF- seguido de una versión número del formulario 1.N, donde N es un dígito entre 0 y 7. Un lector conforme aceptará los archivos con cualquiera de los siguientes encabezados:% PDF-1.0, % PDF- 1.1,% PDF-1.2,% PDF-1.3,% PDF-1.4, % PDF-1.5,% PDF-1.6,% PDF-1.7 Comienzo con PDF 1.4, la entrada de Versión en el diccionario del catálogo del documento (ubicado en a través de la entrada Root en el archivo del remolque, como se describe en 7.5.5, "Archivo Remolque"), si está presente, se usará en lugar de la versión especificada en el encabezado.

Si un archivo PDF contiene datos binarios, como la mayoría (ver 7.2, "léxicas convenios"), la línea de cabecera se ser seguida inmediatamente por una línea de comentario que contiene al menos cuatro binarios caracteres, es decir , caracteres cuyos códigos son 128 o más. Esto garantiza el comportamiento adecuado de las aplicaciones de transferencia de archivos que inspeccionan los datos cerca de al comienzo de un archivo para determinar si se trata el contenido del archivo como texto o como binario.

Por supuesto, usted puede hacer un control "más profundo" de cada archivo mediante la comprobación de más elementos específicos del archivo.

+0

cualquier código de muestra, roygbiv? – Kiquenet

0

puede utilizar Myrmec para identificar el tipo de archivo, esta biblioteca utiliza la cabeza de bytes del archivo. esta biblioteca disponible en nuget "Myrmec", y este es el repositorio, myrmec también es compatible con el tipo de mimo, puedes probarlo. el código se desea:

// create a sniffer instance. 
Sniffer sniffer = new Sniffer(); 

// populate with mata data. 
sniffer.Populate(FileTypes.CommonFileTypes); 

// get file head byte, may be 20 bytes enough. 
byte[] fileHead = ReadFileHead(); 

// start match. 
List<string> results = sniffer.Match(fileHead); 

y obtener el tipo MIME:

List<string> result = sniffer.Match(head); 

cadena mimeType = MimeTypes.GetMimeType (result.First());

pero que tiff ayuda única "49 49 2A 00" y "4D 4D 00 2A" dos firma, si tiene más se puede añadir a su auto, puede ser que usted puede ver el archivo léame de myrmec en busca de ayuda. myrmec github repo

Cuestiones relacionadas