2013-03-01 6 views
8

Ich versuche, eine Binärdatei aus dem Dateisystem zu lesen und dann Base64 in JavaScript zu kodieren. Ich verwende die FileReader API, um die Daten zu lesen und den Base64-Encoder gefunden here.Lesen und Base64 codieren eine Binärdatei

Der Code, den ich habe scheint zu arbeiten, das Problem ist, dass die generierten base64 Daten falsch sind. Hier ist, was ich bisher habe:

function saveResource() { 
    var file = $(".resourceFile")[0].files[0]; 

    var reader = new FileReader(); 
    reader.onload = function(evt) { 
     var fileData = evt.target.result; 
     var bytes = new Uint8Array(fileData); 
     var binaryText = ''; 

     for (var index = 0; index < bytes.byteLength; index++) { 
      binaryText += String.fromCharCode(bytes[index]); 
     } 

     console.log(Base64.encode(binaryText)); 

    }; 
    reader.readAsArrayBuffer(file); 
}; 

Hier ist die Datei Ich teste mit (es ist ein 100x100 blaues Quadrat):

enter image description here

zu einem online base64 decoder/encoder Laut, sollte diese Datei verschlüsseln zu:

/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIy MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4 + Tl5ufo6erx8vP09fb3 + Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3 + Pn6/9oADAMBAAIRAxEAPwDxyiiiv3E8wKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA // Z

... sondern, was ich aus dem JavaScript bekommen ist:

W7/DmMO/w6AAEEpGSUYAAQIAAAEAAQAAw7/DmwBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDLDv8ObAEMBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMsO/w4AAEQgAZABkAwEiAAIRAQMRAcO/w4QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoLw7/DhADCtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDLCgcKRwqEII0LCscOBFVLDkcOwJDNicsKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5esKDwoTChcKGwofCiMKJworCksKTwpTClcKWwpfCmMKZwprCosKjwqTCpcKmwqfCqMKpwqrCssKzwrTCtcK2wrfCuMK5wrrDgsODw4TDhcOGw4fDiMOJw4rDksOTw5TDlcOWw5fDmMOZw5rDocOiw6PDpMOlw6bDp8Oow6nDqsOxw7LDs8O0w7XD tsO3w7jDucO6w7/DhAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgvDv8OEAMK1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIywoEIFELCkcKhwrHDgQkjM1LDsBVicsORChYkNMOhJcOxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXrCgsKDwoTChcKGwofCiMKJworCksKTwpTClcKWwpfCmMKZwprCosKjwqTCpcKmwqfCqMKpwqrCssKzwrTCtcK2wrfCuMK5wrrDgsODw4TDhcOGw4fDiMOJw4rDksOTw5TDlcOWw5fDmMOZw5rDosOjw6TDpcOmw6fDqMOpw6rDssOzw7TDtcO2w7fDuMO5w7rDv8OaAAwDAQACEQMRAD8Aw7HDiijCosK/cTzDgMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooAMKiwoooA8O/w5k =

Wenn ich eine Schätzung riskieren müsste, würde ich sagen, dass das Problem etwas mit nicht druckbaren Zeichen in den binären Daten zu tun hat (wenn ich ein Klartextdokument kodiere, funktioniert das gut). Aber was ist der beste Ansatz, um das Problem zu umgehen?

bearbeiten

Es sieht aus wie dies ein Problem mit der Base64-Bibliothek selbst sein kann (oder, wenn nicht, dann mit, wie die Uint8Array für den Bibliotheksaufruf in einen String ausgepackt ist). Wenn ich stattdessen die btoa()-Funktion des Browsers verwende und die Uint8ArraybinaryText direkt übergebe, funktioniert das. Schade, dass diese Funktion nicht in allen Browsern existiert.

Antwort

8

Und Google zur Rettung. Ich fand den folgenden Code, der die Eingabedaten als ein einfaches Array von "Bytes" (Zahlen zwischen 0 und 255, inklusive; funktioniert auch, wenn die Uint8Array wird direkt übergeben), und fügte sie in die Bibliothek, die ich verwendet wurde :

//note: it is assumed that the Base64 object has already been defined 
//License: Apache 2.0 
Base64.byteToCharMap_ = null; 
Base64.charToByteMap_ = null; 
Base64.byteToCharMapWebSafe_ = null; 
Base64.charToByteMapWebSafe_ = null; 
Base64.ENCODED_VALS_BASE = 
    'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 
    'abcdefghijklmnopqrstuvwxyz' + 
    ''; 

/** 
* Our default alphabet. Value 64 (=) is special; it means "nothing." 
* @type {string} 
*/ 
Base64.ENCODED_VALS = Base64.ENCODED_VALS_BASE + '+/='; 
Base64.ENCODED_VALS_WEBSAFE = Base64.ENCODED_VALS_BASE + '-_.'; 

/** 
* Base64-encode an array of bytes. 
* 
* @param {Array.<number>|Uint8Array} input An array of bytes (numbers with 
*  value in [0, 255]) to encode. 
* @param {boolean=} opt_webSafe Boolean indicating we should use the 
*  alternative alphabet. 
* @return {string} The base64 encoded string. 
*/ 
Base64.encodeByteArray = function(input, opt_webSafe) { 
    Base64.init_(); 

    var byteToCharMap = opt_webSafe ? 
         Base64.byteToCharMapWebSafe_ : 
         Base64.byteToCharMap_; 

    var output = []; 

    for (var i = 0; i < input.length; i += 3) { 
    var byte1 = input[i]; 
    var haveByte2 = i + 1 < input.length; 
    var byte2 = haveByte2 ? input[i + 1] : 0; 
    var haveByte3 = i + 2 < input.length; 
    var byte3 = haveByte3 ? input[i + 2] : 0; 

    var outByte1 = byte1 >> 2; 
    var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4); 
    var outByte3 = ((byte2 & 0x0F) << 2) | (byte3 >> 6); 
    var outByte4 = byte3 & 0x3F; 

    if (!haveByte3) { 
     outByte4 = 64; 

     if (!haveByte2) { 
     outByte3 = 64; 
     } 
    } 

    output.push(byteToCharMap[outByte1], 
       byteToCharMap[outByte2], 
       byteToCharMap[outByte3], 
       byteToCharMap[outByte4]); 
    } 

    return output.join(''); 
}; 

/** 
* Lazy static initialization function. Called before 
* accessing any of the static map variables. 
* @private 
*/ 
Base64.init_ = function() { 
    if (!Base64.byteToCharMap_) { 
    Base64.byteToCharMap_ = {}; 
    Base64.charToByteMap_ = {}; 
    Base64.byteToCharMapWebSafe_ = {}; 
    Base64.charToByteMapWebSafe_ = {}; 

    // We want quick mappings back and forth, so we precompute two maps. 
    for (var i = 0; i < Base64.ENCODED_VALS.length; i++) { 
     Base64.byteToCharMap_[i] = 
      Base64.ENCODED_VALS.charAt(i); 
     Base64.charToByteMap_[Base64.byteToCharMap_[i]] = i; 
     Base64.byteToCharMapWebSafe_[i] = 
      Base64.ENCODED_VALS_WEBSAFE.charAt(i); 
     Base64.charToByteMapWebSafe_[ 
      Base64.byteToCharMapWebSafe_[i]] = i; 
    } 
    } 
}; 

der vollständige Code für die Bibliothek, die die oben genannten Funktionen enthält, ist available here, aber in seiner nicht-modifizierten Form erscheint es auf eine Reihe von anderen Bibliotheken abhängen. Die oben erwähnte leicht gehackte Version sollte für jeden funktionieren, der nur eine schnelle Lösung für dieses Problem benötigt.

+0

Das ist genau das, was ich suche - jede Chance, den Dekodierungs Teil veröffentlichen? – Graham

+1

Ich habe keine eigene Version des Dekodierungsteils, da ich sie nicht für meine Zwecke brauchte (die Dekodierung erfolgt serverseitig in meinem Fall). Allerdings ist der ursprüngliche Quellcode von Google hier verfügbar: http://docs.closure-library.googlecode.com/git/closure_goog_crypt_base64.js.source.html – aroth

+0

Ja, geschaut, aber es hat die Abhängigkeiten, die Sie haben entfernt in Ihrem Encoding-Stück, so habe ich auf etwas ähnliches gehofft, aber danke für die Antwort sowieso. – Graham

2

Behandle die Binärdatei als Array-Puffer, dies ist unabhängig von einer Zeichenkodierung. Ihr blaues Quadrat (.jpg) hat 361 native Bytes, bedeutet Oktette von 0..255 (dezimal) und sie sind keine Zeichen!

Es bedeutet: Verwenden Sie ArrayBuffer für die Codierung dieser Base64 mit gut bekannten base64-Algorithmus.

Mit Perl zurück zum Ursprung, zeigt den blau-Platz wie oben:

my $fh = IO::File->new; 
$fh->open("d:/tmp/x.jpg", O_BINARY|O_CREAT|O_RDWR|O_TRUNC) or die $!; 

$fh->print(decode_base64("/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBD 
AQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABkAGQDASIAAhEBAxEB/8QAFQABAQAA 
AAAAAAAAAAAAAAAAAAf/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAUH/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMR 
AD8AjgDcUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB//2Q== 
")); 


$fh->close;