#!/usr/bin/env node "use strict";const commander=require("commander"),fs=require("fs");let e=!1;function disableDebug(){e=!1}function logd(i,...r){if(!e)return;const n=new Date,s=n.getFullYear(),o=n.getMonth()+1,c=n.getDate(),d=n.getHours(),a=n.getMinutes(),u=n.getSeconds(),f=`[${`\x1B[36m${`${s}-${o}-${c} ${d}:${a}:${u}`}\x1B[0m`}] ${i}`;console.log(f,...r)}const t=new TextDecoder("utf-8",{fatal:!0});function isUtf8(i){typeof i=="string"&&(i=new TextEncoder().encode(i));try{t.decode(i)}catch(r){if(r.name==="TypeError")return!1;throw r}return!0}class Bdecoder{constructor(){this.curosr=0,this.textDecoder=new TextDecoder}static isByteKey(r){if(typeof r!="string"||!r.startsWith("Unit8Array[")||!r.endsWith("]"))return!1;const n=r.replace("Unit8Array[","").replace("]","").split(",");try{for(const s of n){const o=parseInt(s);if(!Number.isInteger(o)||o<0||o>255)return!1}}catch{return!1}return!0}static byteKeyToUint8Array(r){if(!this.isByteKey(r))return;const n=r.replace("Unit8Array[","").replace("]","").split(","),s=new Uint8Array(n.length);for(let o=0;or.length)return logd(`[readBytes] read bytes out of range, curosr is ${this.curosr}, length is ${n}, data length is ${r.length}`),new Uint8Array;const s=r.slice(this.curosr,this.curosr+n);return this.curosr+=n,s}backCursor(r=1){this.curosr-=r}parse(r){const n=this.readBytes(r);if(logd(`[decode] read next byte ${this.textDecoder.decode(n)}`),n.length===0){logd("[decode] head bytes is null, return null");return}switch(String.fromCharCode(n[0])){case"i":return logd("[decode] start parse integer"),this.decodeInteger(r);case"l":return logd("[decode] start parse list"),this.decodeList(r);case"d":return logd("[decode] start parse dict"),this.decodeDict(r);default:return logd("[decode] start parse byte string"),this.backCursor(),this.decodeByteString(r)}}decodeInteger(r){logd("[decodeInteger] start read int bytes length");const n=this.readUntil(r,"e"),s=parseInt(this.textDecoder.decode(n));return logd(`[decodeInteger] decoded integer is ${s}`),s}decodeByteString(r){logd("[decodeByteString] start read string bytes length");const n=this.readUntil(r,":");logd(`[decodeByteString] readed lengthBuffer value is ${n}`);const s=parseInt(this.textDecoder.decode(n));logd(`[decodeByteString] next string bytes length is ${s}`);const o=this.readBytes(r,s);logd(`[decodeByteString] readed stringBuffer length is ${o?o.length:0}`);const c=this.textDecoder.decode(o);return isUtf8(o)?c:(logd("[decodeByteString] string is not utf8, return number array"),o)}decodeList(r){const n=[];for(;;){const s=this.readBytes(r);if(s.length===0||String.fromCharCode(s[0])==="e")break;this.backCursor();const o=this.parse(r);if(o==null)break;n.push(o)}return n}decodeDict(r){let n={};for(;;){const s=this.readBytes(r);if(s.length===0||String.fromCharCode(s[0])==="e")break;this.backCursor(),logd("[decodeDict] start parse dict key");let o=this.decodeByteString(r);o instanceof Uint8Array&&(o=`Unit8Array[${Array.from(o).join(",")}]`),logd(`[decodeDict] key is '${o}'`),logd("[decodeDict] start parse dict value"),n[o]=this.parse(r)}return n}readUntil(r,n){logd(`[readUntil] '${n}'`);const s=[];for(;;){const o=this.readBytes(r);if(logd(`[readUntil] readed bytes is ${o}`),o.length===0||String.fromCharCode(...o)===n){logd("[readUntil] reached stop char");break}s.push(o)}return Uint8Array.from(Buffer.concat(s))}}function isBencodeInteger(i){return typeof i=="number"&&Number.isInteger(i)}function isBencodeDict(i){return typeof i=="object"&&i!==null&&!Array.isArray(i)}function isBencodeList(i){return Array.isArray(i)}function isBencodeString(i){return typeof i=="string"||i instanceof Uint8Array||i instanceof Buffer}class Bencoder{constructor(){this.te=new TextEncoder}encode(r){if(isBencodeString(r))return logd("start to encode string"),this.encodeByteString(r);if(isBencodeInteger(r))return logd("start to encode integer"),this.encodeInt(r);if(isBencodeList(r))return logd("start to encode list"),this.encodeList(r);if(isBencodeDict(r))return logd("start to encode dict"),this.encodeDict(r);throw new Error(`unsupported data type '${typeof r}'`)}encodeByteString(r){if(r==null)throw new Error("undefined or null string isn't be supported to be encode");r instanceof Buffer||(r=Buffer.from(r));const n=[this.te.encode(`${r.length}:`)];return n.push(r),Uint8Array.from(Buffer.concat(n))}encodeInt(r){if(!Number.isInteger(r))throw new Error("bencode only support encode integer");return this.te.encode(`i${r}e`)}encodeList(r){logd(" start encodeList");const n=[this.te.encode("l")];for(const s of r)logd(` start itre ${s}`),n.push(this.encode(s));return logd(" end encodeList"),n.push(this.te.encode("e")),Uint8Array.from(Buffer.concat(n))}encodeDict(r){const n=[this.te.encode("d")];let s=Object.keys(r);s.sort();for(let o=0;o","string or file to decode").option("-f, --file","bencoded file",!1).option("-p, --pretty","pretty output",!1).action((r,n)=>{const{file:s,pretty:o}=n,c=new TextEncoder;let d;if(s){if(!fs.existsSync(r)){console.log(`File ${r} does not exist.`);return}d=fs.readFileSync(r)}else d=c.encode(r);const a=new Bdecoder().decode(d),u=JSON.stringify(a,null,o?2:0);console.log(u)}),i.parse()}exports.Bdecoder=Bdecoder,exports.Bencoder=Bencoder,exports.isBencodeDict=isBencodeDict,exports.isBencodeInteger=isBencodeInteger,exports.isBencodeList=isBencodeList,exports.isBencodeString=isBencodeString;