mirror of
https://github.com/networkmastered/obsidian-compress.git
synced 2026-07-22 05:41:28 +00:00
Rewrite compression before release
This commit is contained in:
parent
51c5aa7b02
commit
bafa5da70a
5 changed files with 4730 additions and 79 deletions
170
main.ts
170
main.ts
|
|
@ -1,8 +1,8 @@
|
|||
import { App, MarkdownView, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { inflate, deflate } from "./util/pakoMinified"
|
||||
import { BB } from "./util/BB"
|
||||
import { encodeSafe, decodeSafe } from "./util/runlength"
|
||||
|
||||
// import { inflate, deflate } from "./util/pakoMinified"
|
||||
// import { BB } from "./util/BB"
|
||||
// import { encodeSafe, decodeSafe } from "./util/runlength"
|
||||
import { netcompress, netdecompress } from "./util/networkmastercompression"
|
||||
|
||||
interface compressorSettingsData {
|
||||
// mySetting: string;
|
||||
|
|
@ -62,12 +62,10 @@ export default class compressorPlugin extends Plugin {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
}, 10)
|
||||
return hook
|
||||
}
|
||||
)
|
||||
|
||||
this.registerEvent(this.app.workspace.on("file-open", (file) => {
|
||||
if (file && file.extension == "ctxt" && globalLeafs.length <= 0 && (new Date().getTime() - loadTime) < 1000) {
|
||||
this.app.workspace.getMostRecentLeaf()?.openFile(file)
|
||||
|
|
@ -78,7 +76,6 @@ export default class compressorPlugin extends Plugin {
|
|||
})
|
||||
}
|
||||
}))
|
||||
|
||||
this.registerEvent(this.app.vault.on('modify', (file) => {
|
||||
let file2 = this.app.vault.getFileByPath(file.path)
|
||||
if (file2 && file2.extension == "ctxt") {
|
||||
|
|
@ -245,77 +242,106 @@ export default class compressorPlugin extends Plugin {
|
|||
await this.saveData(this.settings);
|
||||
}
|
||||
}
|
||||
// function compressfile(data: string, notice?: boolean, settings?: compressorSettingsData) {
|
||||
// if (notice) new Notice("Started", 3000)
|
||||
// const comp = deflate(data)
|
||||
// let inf = inflate(comp)
|
||||
// if (inf && typeof (inf) != "string" && new TextDecoder().decode(inf) != data) {
|
||||
// if (notice) new Notice("Revert is corrupted.", 3000)
|
||||
// throw new Error("Revert not same,")
|
||||
// }
|
||||
// if (comp) {
|
||||
// if (notice) new Notice("MEST", 3000)
|
||||
// let bb = new BB()
|
||||
// comp.forEach((byte: Number) => {
|
||||
// // console.log(byte)
|
||||
// bb.WU(8,byte)
|
||||
// })
|
||||
// if (notice) new Notice("SWAP", 3000)
|
||||
// // let linkblk = ""
|
||||
// // ;[...data.matchAll(/\[\[[^\]]*\]\]/gm)].forEach((match) => {
|
||||
// // console.log(match)
|
||||
// // linkblk += match[0]
|
||||
// // })
|
||||
// let encd = encodeSafe(bb.G())
|
||||
// if (notice) new Notice("RLE", 3000)
|
||||
// if (encd) {
|
||||
// if (notice) new Notice("METADATA SET.", 3000)
|
||||
// let content = `DATABLK` + encd
|
||||
// if (content && content.length < data.length) {
|
||||
// if (notice) new Notice("Success!")
|
||||
// if (settings && settings.PrintResult) {
|
||||
// NoticePool.push(new Notice(`Compression:\nratio:${((content.length / data.length) * 100).toFixed(1)}%`))
|
||||
// }
|
||||
// return content
|
||||
// } else {
|
||||
// if (notice) new Notice("File isnt smaller.")
|
||||
// }
|
||||
// } else {
|
||||
// new Notice("Encoder failure.")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// function decompressfile(data: string, notice?: boolean) {
|
||||
// if (notice) new Notice("START", 3000)
|
||||
// let bb = new BB()
|
||||
// bb.F(decodeSafe(data.substring(data.indexOf("DATABLK") + 7)))
|
||||
// let precont: number[] = []
|
||||
// while (true) {
|
||||
// let now = bb.RU(8)
|
||||
// if (!isNaN(now)) {
|
||||
// precont[precont.length] = now
|
||||
// } else break
|
||||
// }
|
||||
// if (notice) new Notice("OUT", 3000)
|
||||
// let cont = new Uint8Array(precont)
|
||||
// if (notice) console.log(precont)
|
||||
// if (notice) console.log(cont)
|
||||
// if (notice) new Notice("SWAP", 3000)
|
||||
// if (cont && cont.length > 0) {
|
||||
// if (notice) new Notice("INF", 3000)
|
||||
// let decomp = inflate(cont)
|
||||
// if (notice) console.log(decomp)
|
||||
// if (notice) new Notice("DONE, DECODE", 3000)
|
||||
// if (typeof (decomp) == "object") {
|
||||
// decomp = new TextDecoder().decode(decomp)
|
||||
// if (notice) new Notice("Success!")
|
||||
// return decomp
|
||||
// } else {
|
||||
// if (notice) new Notice("Failed.")
|
||||
// }
|
||||
// } else {
|
||||
// if (notice) new Notice("Couldnt Decompress.")
|
||||
// }
|
||||
// }
|
||||
function compressfile(data: string, notice?: boolean, settings?: compressorSettingsData) {
|
||||
if (notice) new Notice("Started", 3000)
|
||||
const comp = deflate(data)
|
||||
let inf = inflate(comp)
|
||||
if (inf && typeof (inf) != "string" && new TextDecoder().decode(inf) != data) {
|
||||
if (notice) new Notice("Revert is corrupted.", 3000)
|
||||
throw new Error("Revert not same,")
|
||||
}
|
||||
if (comp) {
|
||||
if (notice) new Notice("MEST", 3000)
|
||||
let bb = new BB()
|
||||
comp.forEach((byte: Number) => {
|
||||
// console.log(byte)
|
||||
bb.WU(byte)
|
||||
})
|
||||
if (notice) new Notice("SWAP", 3000)
|
||||
// let linkblk = ""
|
||||
// ;[...data.matchAll(/\[\[[^\]]*\]\]/gm)].forEach((match) => {
|
||||
// console.log(match)
|
||||
// linkblk += match[0]
|
||||
// })
|
||||
let encd = encodeSafe(bb.G())
|
||||
if (notice) new Notice("RLE", 3000)
|
||||
if (encd) {
|
||||
if (notice) new Notice("METADATA SET.", 3000)
|
||||
let content = `DATABLK` + encd
|
||||
if (content && content.length < data.length) {
|
||||
if (notice) new Notice("Success!")
|
||||
if (settings && settings.PrintResult) {
|
||||
NoticePool.push(new Notice(`Compression:\nratio:${((content.length / data.length) * 100).toFixed(1)}%`))
|
||||
}
|
||||
return content
|
||||
} else {
|
||||
if (notice) new Notice("File isnt smaller.")
|
||||
}
|
||||
} else {
|
||||
new Notice("Encoder failure.")
|
||||
if (notice) new Notice("Started C", 3000)
|
||||
let result: (string | undefined) = ""
|
||||
try {
|
||||
result = netcompress(data)
|
||||
if (notice) new Notice("Done!")
|
||||
if (settings && settings.PrintResult && result) {
|
||||
NoticePool.push(new Notice(`Compression:\nratio:${((result.length / data.length) * 100).toFixed(1)}%`))
|
||||
}
|
||||
} catch (err) {
|
||||
new Notice(err, 3000)
|
||||
throw new Error(err)
|
||||
}
|
||||
if (result == "" || !result) throw new Error("Empty")
|
||||
return result
|
||||
}
|
||||
function decompressfile(data: string, notice?: boolean) {
|
||||
if (notice) new Notice("START", 3000)
|
||||
let bb = new BB()
|
||||
bb.F(decodeSafe(data.substring(data.indexOf("DATABLK") + 7)))
|
||||
let precont: number[] = []
|
||||
while (true) {
|
||||
let now = bb.RU()
|
||||
if (!isNaN(now)) {
|
||||
precont[precont.length] = now
|
||||
} else break
|
||||
}
|
||||
if (notice) new Notice("OUT", 3000)
|
||||
let cont = new Uint8Array(precont)
|
||||
if (notice) console.log(precont)
|
||||
if (notice) console.log(cont)
|
||||
if (notice) new Notice("SWAP", 3000)
|
||||
if (cont && cont.length > 0) {
|
||||
if (notice) new Notice("INF", 3000)
|
||||
let decomp = inflate(cont)
|
||||
if (notice) console.log(decomp)
|
||||
if (notice) new Notice("DONE, DECODE", 3000)
|
||||
if (typeof (decomp) == "object") {
|
||||
decomp = new TextDecoder().decode(decomp)
|
||||
if (notice) new Notice("Success!")
|
||||
return decomp
|
||||
} else {
|
||||
if (notice) new Notice("Failed.")
|
||||
}
|
||||
} else {
|
||||
if (notice) new Notice("Couldnt Decompress.")
|
||||
if (notice) new Notice("Started D", 3000)
|
||||
let result: (string | undefined) = ""
|
||||
try {
|
||||
result = netdecompress(data)
|
||||
if (notice) new Notice("Done!")
|
||||
} catch (err) {
|
||||
new Notice(err, 3000)
|
||||
throw new Error(err)
|
||||
}
|
||||
if (result == "" || !result) throw new Error("Empty")
|
||||
return result
|
||||
}
|
||||
class compressorSettings extends PluginSettingTab {
|
||||
plugin: compressorPlugin;
|
||||
|
|
|
|||
17
util/BB.js
17
util/BB.js
|
|
@ -34,16 +34,19 @@ export class BB {
|
|||
}
|
||||
return str
|
||||
}
|
||||
WU(value) {
|
||||
for (let i = 0; i < 8; i++) {
|
||||
WU(r, val) {
|
||||
for (let i = 0; i < r; i++) {
|
||||
this.PT++
|
||||
this.BB[this.PT] = value % 2
|
||||
value = Math.floor(value / 2)
|
||||
this.BB[this.PT] = val % 2
|
||||
val = Math.floor(val / 2)
|
||||
}
|
||||
}
|
||||
RU() {
|
||||
let r = this.BB[this.PT+1] * this.PO[0] + this.BB[this.PT + 2] * this.PO[1] + this.BB[this.PT + 3] * this.PO[2] + this.BB[this.PT + 4] * this.PO[3] + this.BB[this.PT + 5] * this.PO[4] + this.BB[this.PT + 6] * this.PO[5] + this.BB[this.PT + 7] * this.PO[6] + this.BB[this.PT + 8] * this.PO[7]
|
||||
this.PT += 8
|
||||
RU(val) {
|
||||
let r = 0
|
||||
for (let i = 0; i < val; i++) {
|
||||
this.PT++
|
||||
r += this.BB[this.PT] * this.PO[i]
|
||||
}
|
||||
return r
|
||||
}
|
||||
}
|
||||
4098
util/dictionaryBIG.json
Normal file
4098
util/dictionaryBIG.json
Normal file
File diff suppressed because it is too large
Load diff
282
util/networkmastercompression.js
Normal file
282
util/networkmastercompression.js
Normal file
File diff suppressed because one or more lines are too long
242
util/runlengthMatch.js
Normal file
242
util/runlengthMatch.js
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
// - - -
|
||||
// # LZ77
|
||||
// ** A minimal LZ77 [de]compressor **
|
||||
var LZ77 = function () {
|
||||
// ##### Private Variables
|
||||
var
|
||||
self = {}
|
||||
, settings = {
|
||||
refPrefix: '`',
|
||||
refIntBase: 96,
|
||||
refIntFloorCode: ' '.charCodeAt(0),
|
||||
refIntCeilCode: undefined,
|
||||
maxStringDistance: undefined,
|
||||
minStringLength: 5,
|
||||
maxStringLength: undefined,
|
||||
defaultWindow: 144,
|
||||
maxWindow: undefined,
|
||||
windowLength: undefined
|
||||
}
|
||||
;
|
||||
|
||||
// ##### Public Variables
|
||||
|
||||
// ##### Private Methods
|
||||
var setup = function (params) {
|
||||
params = params || {};
|
||||
settings = extend(settings, params);
|
||||
|
||||
settings.refIntCeilCode = settings.refIntFloorCode + settings.refIntBase - 1;
|
||||
settings.maxStringDistance = Math.pow(settings.refIntBase, 2) - 1;
|
||||
settings.maxStringLength = Math.pow(settings.refIntBase, 1) - 1 + settings.minStringLength;
|
||||
settings.maxWindow = settings.maxStringDistance + settings.minStringLength;
|
||||
};
|
||||
|
||||
// #### each()
|
||||
// >`@param obj [collection]` our source collection
|
||||
// >`@param iterator [function]` the function that will be called for each element in the collection
|
||||
// >`@param context [object]` the context our iterator should operate within
|
||||
//
|
||||
// essentially copied from underscore.js
|
||||
var each = function (obj, iterator, context) {
|
||||
var breaker = {};
|
||||
if (obj === null) { return; }
|
||||
if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) {
|
||||
obj.forEach(iterator, context);
|
||||
} else if (obj.length === +obj.length) {
|
||||
for (var i = 0, l = obj.length; i < l; i++) {
|
||||
if (iterator.call(context, obj[i], i, obj) === breaker) { return; }
|
||||
}
|
||||
} else {
|
||||
for (var key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
if (iterator.call(context, obj[key], key, obj) === breaker) { return; }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// #### extend()
|
||||
// >`@param obj [object]` our destination object
|
||||
// >`@params * [object(s)]` objects that will overwrite the data in the destination object, in order
|
||||
//
|
||||
// essentially copied from underscore.js
|
||||
var extend = function (obj) {
|
||||
each(Array.prototype.slice.call(arguments, 1), function (source) {
|
||||
if (source) {
|
||||
for (var prop in source) {
|
||||
obj[prop] = source[prop];
|
||||
}
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
|
||||
var encodeRefInt = function (value, width) {
|
||||
if ((value >= 0) && (value < (Math.pow(settings.refIntBase, width) - 1))) {
|
||||
var encoded = '';
|
||||
while (value > 0) {
|
||||
encoded = (String.fromCharCode((value % settings.refIntBase) + settings.refIntFloorCode)) + encoded;
|
||||
value = Math.floor(value / settings.refIntBase);
|
||||
}
|
||||
var missingLength = width - encoded.length;
|
||||
var i = 0;
|
||||
for (; i < missingLength; i++) {
|
||||
encoded = String.fromCharCode(settings.refIntFloorCode) + encoded;
|
||||
}
|
||||
return encoded;
|
||||
} else {
|
||||
throw 'Reference int out of range: ' + value + ' (width = ' + width + ')';
|
||||
}
|
||||
};
|
||||
|
||||
var encodeRefLength = function (length) {
|
||||
return encodeRefInt(length - settings.minStringLength, 1);
|
||||
};
|
||||
|
||||
var decodeRefInt = function (data, width) {
|
||||
var
|
||||
value = 0
|
||||
, charCode
|
||||
, i = 0
|
||||
;
|
||||
for (; i < width; i++) {
|
||||
value *= settings.refIntBase;
|
||||
charCode = data.charCodeAt(i);
|
||||
if ((charCode >= settings.refIntFloorCode) && (charCode <= settings.refIntCeilCode)) {
|
||||
value += charCode - settings.refIntFloorCode;
|
||||
} else {
|
||||
throw 'Invalid char code in reference int: ' + charCode;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
var decodeRefLength = function (data) {
|
||||
return decodeRefInt(data, 1) + settings.minStringLength;
|
||||
};
|
||||
|
||||
|
||||
// ##### Public Methods
|
||||
|
||||
// #### LZ77.compress()
|
||||
// >`@param source [string]` the source string we will be compressing
|
||||
// >`@param params [object]` this allows us to overwrite defaults at call-time
|
||||
//
|
||||
// This is our compression method, taking the input string (and allowing for call-time
|
||||
// paramters) and returning the compressed representation
|
||||
self.compress = function (source, params) {
|
||||
if (Object.prototype.toString.call(source) !== '[object String]') { return false; }
|
||||
|
||||
setup(params);
|
||||
|
||||
var windowLength = settings.windowLength || settings.defaultWindow;
|
||||
if (windowLength > settings.maxWindow) { throw 'Window length too large'; }
|
||||
|
||||
var
|
||||
compressed = ''
|
||||
, pos = 0
|
||||
, lastPos = source.length - settings.minStringLength
|
||||
;
|
||||
|
||||
while (pos < lastPos) {
|
||||
var
|
||||
searchStart = Math.max(pos - windowLength, 0)
|
||||
, matchLength = settings.minStringLength
|
||||
, foundMatch = false
|
||||
, bestMatch = {
|
||||
distance: settings.maxStringDistance,
|
||||
length: 0
|
||||
}
|
||||
, newCompressed = null
|
||||
, isValidMatch
|
||||
, realMatchLength
|
||||
;
|
||||
|
||||
while ((searchStart + matchLength) < pos) {
|
||||
isValidMatch = ((source.substr(searchStart, matchLength) === source.substr(pos, matchLength)) && (matchLength < settings.maxStringLength));
|
||||
if (isValidMatch) {
|
||||
matchLength++;
|
||||
foundMatch = true;
|
||||
} else {
|
||||
realMatchLength = matchLength - 1;
|
||||
if (foundMatch && (realMatchLength > bestMatch.length)) {
|
||||
bestMatch.distance = pos - searchStart - realMatchLength;
|
||||
bestMatch.length = realMatchLength;
|
||||
}
|
||||
matchLength = settings.minStringLength;
|
||||
searchStart++;
|
||||
foundMatch = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestMatch.length) {
|
||||
newCompressed = settings.refPrefix + encodeRefInt(bestMatch.distance, 2) + encodeRefLength(bestMatch.length);
|
||||
pos += bestMatch.length;
|
||||
} else {
|
||||
if (source.charAt(pos) !== settings.refPrefix) {
|
||||
newCompressed = source.charAt(pos);
|
||||
} else {
|
||||
newCompressed = settings.refPrefix + settings.refPrefix;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
compressed += newCompressed;
|
||||
}
|
||||
return compressed + source.slice(pos).replace(/`/g, '``');
|
||||
};
|
||||
|
||||
// #### LZ77.decompress()
|
||||
// >`@param source [string]` the source string of compressed data
|
||||
// >`@param params [object]` this allows us to overwrite defaults at call-time
|
||||
//
|
||||
// decompression method, taking the compressed data (as a string, and allowing for
|
||||
// call-time paramters) and returning the decompressed data
|
||||
self.decompress = function (source, params) {
|
||||
if (Object.prototype.toString.call(source) !== '[object String]') { return false; }
|
||||
|
||||
var
|
||||
decompressed = ''
|
||||
, pos = 0
|
||||
, currentChar
|
||||
, nextChar
|
||||
, distance
|
||||
, length
|
||||
;
|
||||
|
||||
setup(params);
|
||||
while (pos < source.length) {
|
||||
currentChar = source.charAt(pos);
|
||||
if (currentChar !== settings.refPrefix) {
|
||||
decompressed += currentChar;
|
||||
pos++;
|
||||
} else {
|
||||
nextChar = source.charAt(pos + 1);
|
||||
if (nextChar !== settings.refPrefix) {
|
||||
distance = decodeRefInt(source.substr(pos + 1, 2), 2);
|
||||
length = decodeRefLength(source.charAt(pos + 3));
|
||||
decompressed += decompressed.substr(decompressed.length - distance - length, length);
|
||||
pos += settings.minStringLength - 1;
|
||||
} else {
|
||||
decompressed += settings.refPrefix;
|
||||
pos += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return decompressed;
|
||||
};
|
||||
|
||||
return self;
|
||||
}();
|
||||
|
||||
if (typeof define !== 'undefined' && define.amd) { // requirejs/amd
|
||||
define([], function () { return LZ77; });
|
||||
} else if (typeof module !== 'undefined' && module.exports) { // node
|
||||
module.exports = LZ77;
|
||||
} else if (window !== undefined) {
|
||||
window.LZ77 = LZ77;
|
||||
}
|
||||
})();
|
||||
Loading…
Reference in a new issue