編集: この問題は UTF-8 変換に要約されます。ここで議論してください: UTF-8: should it hold that string = encode(decode(string))? そうでない場合、それを達成する方法は?
非公式の神田ソフトウェアの APIを使用して、Chrome 拡張機能から PDF ファイルを Evernote に保存しようとしています。基本的に、Thrift を使用し、Evernote API に従ってデータ構造を作成および送信するためのメソッドを提供します。テスト用に、バイト長が 2898 のサンプル PDF ファイルを使用します。
CreateNote() メソッドが呼び出されると、データは最終的に SDK の thrift.js に入り、そこで UTF エンコードされて適切なデータ構造に配置されます。これらの関数は次のように呼び出されます。
writeString:function(str) {
var result = Array.prototype.map.call(this.encode(str).split(""), this.stringToHex); // <----- I tried to skip this encoding for the data body
this.writeI32(result.length);
for (var i = 0; i < result.length; i++) {
this.ra.push(result[i]);
}
},
...
encode:function(string) {
string = string.replace(/\r\n/g, "\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
}
else if ((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
}
else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
},
...
writeI32:function(i32) {
var i32out = new Array();
i32out[0] = 0xff & i32 >> 24;
i32out[1] = 0xff & i32 >> 16;
i32out[2] = 0xff & i32 >> 8;
i32out[3] = 0xff & i32;
var result = Array.prototype.map.call(i32out, this.byteToHex);
for (var i = 0; i < 4; i++) {
this.ra.push(result[i]);
}
},
Thrift がこのレベルでどのように機能するか、およびバイナリ添付本文を含むすべてのデータをエンコードする必要がある理由をよく理解していませんが、ご覧のとおり、PDF のデータ (および他のすべての文字列データが転送されるため) になります。問題) UTF エンコードされているため、.length は 3018 バイトになりました。すべて API を通過し、ファイルは Evernote フロントエンドに表示されますが (写真を参照)、デコードされず、サイズが 3018 バイトであるため、PDF は失敗します。
データ本体のみの encode() 呼び出しをスキップすることで解決策を総当たりしようとしましたが、これによりファイルが何らかの形で破棄されてしまいます。
問題が私の誤解にあるのか、SDK にあるのか、それとも Evernote のバックエンドにあるのか、どうすれば修正できるのか、手がかりを教えてください。私はこれで眠れなくなりました。
参考までに: 次のように、XMLHttpRequest 経由で元のファイルを取得します。
function getLink(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', document.getElementById('url1').value, true);
xhr.responseType = 'text';
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onload = function(e) {
if (this.status == 200) {
// Note: .response instead of .responseText
alert("String(this.response) " + String(this.response).length);
alert("String(this.responseText) " + String(this.responseText).length);
blob = String(this.response);
AddNote1(url, blob, function(response) {
document.getElementById('result').innerHTML += String(response).replace(/\n/g, "<br/>") + "<br/>";
document.getElementById('result').innerHTML += blob.slice(1, 20);
} );
}
};
xhr.send();
}
結果のデータは問題ないように見え、string.length は 2898 です。次に、例で説明されているようにメモを追加します。繰り返しますが、すべてが適切にチェックアウトされ、バイト文字列がそのまま CreateNote() に挿入されるため、これも参照用です。
function AddNote1(Name, ContentFile, callback)
{
var noteStore = get_NoteStore();
var note = new Note();
note.title = Name;
var na = new NoteAttributes();
//na.author = "someone";
na.sourceURL = Name;
na.source = "web.clip";
note.attributes = na;
var data = new Data();
var resource = new Resource();
binaryData = ContentFile;
data.size = binaryData.length;
alert(binaryData.length + '*' + ContentFile.length);
data.bodyHash = raw_md5(binaryData);
data.body = binaryData;
resource.mime = "application/pdf";
resource.data = data;
var resAttributes = new ResourceAttributes();
resAttributes.fileName = String(Name).replace(/^.*[\/\\]/g, '');
resource.attributes = resAttributes;
note.resources = Array(resource);
//important to set correct content
var content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml2.dtd\"><en-note>";
content += String("Oi Wei").replace(/\n/g, "<br/>") + "<br/>";
content += "<en-media type=\"application/pdf\" hash=\"" + md5(binaryData) + "\"/>";
content += "</en-note>";
note.content = content;
//response is a created note
//callback function process response
var response = noteStore.createNote(Eventnote.Auth.get_auth_token(), note);
if (callback !== undefined) {
callback(response);
}