All files / app/core/services content-preview.service.ts

98.14% Statements 53/54
90% Branches 18/20
100% Functions 6/6
97.87% Lines 46/47

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103      1x       7x 28x     7x   6x   5x   4x       3x 3x     2x 2x 1x     1x       1x         7x 6x 6x 6x 6x       3x 1x   2x 2x 2x       9x   3x 3x 2x       1x       2x 2x 2x 1x 1x       1x       2x 2x 261x     2x 1x   2x     2x 2x 2x 1x   2x            
import { Injectable } from '@angular/core';
 
@Injectable({ providedIn: 'root' })
export class ContentPreviewService {
  
  detectContentType(data: Uint8Array): string {
    // Check for common file signatures
    if (data.length >= 4) {
      const header = Array.from(data.slice(0, 4)).map(b => b.toString(16).padStart(2, '0')).join('');
      
      // PNG
      if (header === '89504e47') return 'image/png';
      // JPEG
      if (header.startsWith('ffd8ff')) return 'image/jpeg';
      // GIF
      if (header.startsWith('47494638')) return 'image/gif';
      // PDF
      if (header === '25504446') return 'application/pdf';
    }
    
    // Try to decode as text
    try {
      const text = new TextDecoder('utf-8', { fatal: true }).decode(data.slice(0, 1000));
      
      // Check if it's JSON
      try {
        JSON.parse(text);
        return 'application/json';
      } catch {
        // Not JSON, but is text
        return 'text/plain';
      }
    } catch {
      // Not valid UTF-8, treat as binary
      return 'application/octet-stream';
    }
  }
 
  formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }
 
  formatHashForDisplay(hashValue: string, maxLength = 16): string {
    if (hashValue.length <= maxLength) {
      return hashValue;
    }
    const prefixLength = 6;
    const suffixLength = 8;
    return `${hashValue.substring(0, prefixLength)}...${hashValue.substring(hashValue.length - suffixLength)}`;
  }
 
  generatePreview(data: Uint8Array, format: 'text' | 'json' | 'hex' | 'base64', maxSize = 1000): string {
    switch (format) {
      case 'text':
        try {
          const text = new TextDecoder('utf-8', { fatal: true }).decode(data);
          return text.length > maxSize 
            ? text.substring(0, maxSize) + '...' 
            : text;
        } catch {
          return 'Unable to decode as text';
        }
        
      case 'json':
        try {
          const text = new TextDecoder().decode(data);
          const json = JSON.parse(text);
          const formatted = JSON.stringify(json, null, 2);
          return formatted.length > maxSize
            ? formatted.substring(0, maxSize) + '...'
            : formatted;
        } catch {
          return 'Invalid JSON';
        }
        
      case 'hex':
        const hexBytes = Math.min(data.length, 256);
        let hex = Array.from(data.slice(0, hexBytes))
          .map(b => b.toString(16).padStart(2, '0'))
          .join(' ')
          .toUpperCase();
        if (data.length > hexBytes) {
          hex += ' ...';
        }
        return hex;
        
      case 'base64':
        const base64Bytes = Math.min(data.length, 1000);
        let base64 = btoa(String.fromCharCode(...data.slice(0, base64Bytes)));
        if (data.length > base64Bytes) {
          base64 += '...';
        }
        return base64;
        
      default:
        return 'Unsupported format';
    }
  }
}