Vor einiger Zeit habe ich die Idee gehabt eine Firefox Extension zu schreiben, welche es ermöglicht binäre Dateianhänge aus dem Usenet zu laden. Das ganze hat auch soweit geklappt und funktioniert. Leider nicht in der Geschwindigkeit wie erhofft. Daher habe ich das Projekt eingestellt und möchte nun meinen Yenc Decoder für den Rest der Welt bereitstellen. Vielleicht kann ja einer etwas damit anfangen. Ansonsten seht es einfach als Proof-of-Concept. Es fehlt allerdings noch die CRC Prüfung, ansonsten ist alles notwendige drin.

Wer Interesse hat das Projekt mit mir fortzuführen, soll sich per Kontaktformular bei mir melden. Kompletter Source im erweiterten Teil dieses Beitrags und als Datei hier zum runterladen.

JAVASCRIPT:
  1. /**
  2. * Javascript YencDecoder
  3. * @author Kjell Bublitz
  4. * @license GPL
  5. */
  6. var specialChar = false;
  7.  
  8. var yencDecoder =
  9. {
  10.     yencPart: "",
  11.     yencTotal: "",
  12.     yencLine: "",
  13.     yencSize: "",
  14.     yencName: "",
  15.     yencCRC: "",
  16.     yencPCRC: "",
  17.  
  18.     /**
  19.     * Searches the yEnc Part of a postbody and processes it. Extracting footer and header data,
  20.     * and the binary data itself. Once it has everything it decodes the yEnc Body.
  21.     * @param {String} the complete message
  22.     * @return {Object} yencObject with all infos
  23.     */
  24.     processMessage: function(inText)
  25.     {
  26.         // Reset
  27.         this.yencPart = "";
  28.         this.yencTotal = "";
  29.         this.yencLine = "";
  30.         this.yencSize = "";
  31.         this.yencName = "";
  32.         this.yencCRC = "";
  33.         this.yencPCRC = "";
  34.  
  35.         var ypartIdx = inText.search('=ypart');
  36.         var ypart = inText.match("=ypart.*");
  37.  
  38.         var yheadIdx = inText.search('=ybegin');
  39.         var yhead = inText.match("=ybegin.*");
  40.  
  41.         var yfootIdx = inText.search('=yend');
  42.         var yfoot = inText.match("=yend.*");
  43.  
  44.         var yDataStart = yheadIdx;
  45.         var yDataEnd = yfootIdx;
  46.  
  47.         // CONTROL
  48.         if(ypartIdx != -1)
  49.         {
  50.             thold = ypart[0].length + 1;
  51.             yDataStart = ypartIdx;
  52.         }
  53.  
  54.         if(yhead && yfoot) // we need both
  55.         {
  56.             var thold = yhead[0].length + 1;
  57.             var yencData = inText.substring(yDataStart, yDataEnd).substr( thold );
  58.  
  59.             if(this.parseYencHead(yhead[0]) && this.parseYencFoot(yfoot[0]) && yencData.length> 0)
  60.             {
  61.                 var yObject = {
  62.                       part: this.yencPart,
  63.                       total: this.yencTotal,
  64.                       line: this.yencLine,
  65.                       size: this.yencSize,
  66.                       crc32: this.yencCRC,
  67.                       pcrc: this.yencPCRC,
  68.                       name: this.yencName,
  69.                       data: this.decodeYenc(yencData)
  70.                 };
  71.                 return yObject;
  72.             }
  73.         }
  74.         return false;
  75.     },
  76.     /**
  77.     * Extract the head data from the yenc post. Stuff like size, filename, partnumber, etc..
  78.     * @param {String} the complete =ybegin line
  79.     * @return {Boolean}
  80.     */
  81.     parseYencHead: function(yhead)
  82.     {
  83.         if (typeof yhead == 'string')
  84.         {
  85.                 var yheadSplit = yhead.split(' ');
  86.  
  87.                 for(var x=0;x <yheadSplit.length;x++)
  88.                 {
  89.                 if(yheadSplit[x].match('part=.*')) {
  90.                     this.yencPart = yheadSplit[x].split('=')[1];
  91.                 }
  92.                 if(yheadSplit[x].match('total=.*')) {
  93.                     this.yencTotal = yheadSplit[x].split('=')[1];
  94.                 }
  95.                 if(yheadSplit[x].match('line=.*')) {
  96.                     this.yencLine = yheadSplit[x].split('=')[1];
  97.                 }
  98.                 if(yheadSplit[x].match('size=.*')) {
  99.                     this.yencSize = yheadSplit[x].split('=')[1];
  100.                 }
  101.                 if(yheadSplit[x].match('name=.*')) {
  102.                     this.yencName = yheadSplit[x].split('=')[1];
  103.                 }
  104.             }
  105.             return true;
  106.         }
  107.         return false;
  108.     },
  109.     /**
  110.     * Extract the CRC sum from the ending line
  111.     * @param {String} the complete =yend line
  112.     * @return {Boolean}
  113.     */
  114.     parseYencFoot: function (yfoot)
  115.     {
  116.         if (typeof yfoot == 'string')
  117.         {
  118.                 var yfootSplit = yfoot.split(' ');
  119.  
  120.                 for(var x=0;x <yfootSplit.length;x++)
  121.                 {
  122.                 if(yfootSplit[x].match('part=.*')) {
  123.                     this.yencCRC = yfootSplit[x].split('=')[1];
  124.                 }
  125.                 if(yfootSplit[x].match('total=.*')) {
  126.                     this.yencPCRC = yfootSplit[x].split('=')[1];
  127.                 }
  128.             }
  129.             return true;
  130.         }
  131.         return false;
  132.     },
  133.     /**
  134.     * Decoded char by char.
  135.     * @param {String} Encoded
  136.     * @return {String} Decoded
  137.     */
  138.     decodeYenc: function(yEncoded)
  139.     {
  140.         var yDecoded = "", yencChar, ascChar, percent_done;
  141.  
  142.         for(var c=0;c <yEncoded.length; c++)
  143.         {
  144.             yencChar = this.charToInt(yEncoded[c]);
  145.             ascChar = this.decodeChar(yencChar);
  146.  
  147.             if(specialChar == false) {
  148.                 yDecoded += this.intToChar(ascChar);
  149.             }
  150.         }
  151.         return yDecoded;
  152.     },
  153.     /**
  154.     * Get CharacterCode
  155.     * @param {Char} ASCII Character
  156.     * @return {Integer} Character Code
  157.     */
  158.     charToInt: function(ch)
  159.     {
  160.         var ordZero = '0'.charCodeAt(0);
  161.         return ch.charCodeAt(0);
  162.     },
  163.     /**
  164.     * Get ASCII Character
  165.     * @param {Integer} Character Code
  166.     * @return {Char} ASCII Character
  167.     */
  168.     intToChar: function(ch)
  169.     {
  170.         var ordZero = '0'.charCodeAt(0); //48
  171.         return String.fromCharCode(ch);
  172.     },
  173.     /**
  174.     * Get Yenc Decoded CharCode
  175.     * @param {Integer} Character Code
  176.     * @return {Integer} New Character Code
  177.     */
  178.     decodeChar: function(character)
  179.     {
  180.         var result;
  181.  
  182.         if (character != 61)
  183.         {
  184.             result = specialChar?character-106:character-42;
  185.             specialChar = false;
  186.         }
  187.         else
  188.         {
  189.             specialChar = true;
  190.         }
  191.         return result;
  192.     }
  193. };

Diesen Eintrag kommentieren