From eed374d48b3097d225a5a1dd4dfa5efc74cee6a6 Mon Sep 17 00:00:00 2001 From: Livio <193267+javalc6@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:02:04 +0200 Subject: [PATCH] initial release initial release --- LICENSE.md | 67 + bzip2/BZip2CompressorInputStream.java | 944 ++ bzip2/BZip2Constants.java | 22 + bzip2/BitInputStream.java | 187 + bzip2/CRC.java | 114 + bzip2/CloseShieldFilterInputStream.java | 25 + bzip2/CompressorInputStream.java | 81 + bzip2/CountingInputStream.java | 61 + bzip2/InputStreamStatistics.java | 16 + bzip2/Rand.java | 74 + .../scribunto/ScribuntoException.java | 11 + .../engine/lua/ScribuntoLuaEngine.java | 647 ++ .../engine/lua/interfaces/Languages.java | 25 + .../engine/lua/interfaces/MwHtml.java | 44 + .../engine/lua/interfaces/MwInit.java | 18 + .../engine/lua/interfaces/MwInterface.java | 36 + .../engine/lua/interfaces/MwLanguage.java | 195 + .../engine/lua/interfaces/MwMessage.java | 103 + .../engine/lua/interfaces/MwSite.java | 170 + .../engine/lua/interfaces/MwText.java | 146 + .../engine/lua/interfaces/MwTitle.java | 221 + .../engine/lua/interfaces/MwUri.java | 113 + .../engine/lua/interfaces/MwUstring.java | 26 + .../extensions/scribunto/template/Frame.java | 106 + info/bliki/wiki/template/dates/PHPDate.java | 189 + .../wiki/template/dates/StringToTime.java | 729 ++ .../template/dates/StringToTimeException.java | 17 + lib/StringLib.java | 1225 +++ lib/luaj-jse-3.0.2p.jar | Bin 0 -> 472927 bytes lib/readme.txt | 3 + luabit/bit.lua | 264 + luabit/bit32.lua | 209 + luabit/hex.lua | 99 + luabit/readme.txt | 143 + lualib/libraryUtil.lua | 71 + lualib/mw.hash.lua | 30 + lualib/mw.html.lua | 433 + lualib/mw.language.lua | 189 + lualib/mw.lua | 784 ++ lualib/mw.message.lua | 198 + lualib/mw.site.lua | 86 + lualib/mw.text.lua | 331 + lualib/mw.title.lua | 337 + lualib/mw.uri.lua | 623 ++ lualib/mw.ustring.lua | 108 + lualib/mwInit.lua | 143 + lualib/package.lua | 127 + ustring/README | 51 + ustring/charsets.lua | 3117 ++++++ ustring/lower.lua | 679 ++ ustring/normalization-data.lua | 9450 +++++++++++++++++ ustring/string.lua | 15 + ustring/upper.lua | 715 ++ ustring/ustring.lua | 1260 +++ wiki.html | 1 + wiki/MagicWords.java | 371 + wiki/NameSpaces.java | 200 + wiki/TemplateParser.java | 336 + wiki/TestSuite.java | 334 + wiki/WikiFind.java | 127 + wiki/WikiSplitter.java | 432 + wiki/parserfunctions/Expr.java | 57 + wiki/parserfunctions/FormatDate.java | 47 + wiki/parserfunctions/Formatnum.java | 64 + wiki/parserfunctions/Fullurl.java | 52 + wiki/parserfunctions/Fullurle.java | 52 + wiki/parserfunctions/If.java | 51 + wiki/parserfunctions/Ifeq.java | 58 + wiki/parserfunctions/Iferror.java | 51 + wiki/parserfunctions/Ifexist.java | 51 + wiki/parserfunctions/Ifexpr.java | 65 + wiki/parserfunctions/Invoke.java | 83 + wiki/parserfunctions/Localurl.java | 51 + wiki/parserfunctions/Localurle.java | 51 + wiki/parserfunctions/Padleft.java | 68 + wiki/parserfunctions/Padright.java | 69 + wiki/parserfunctions/ParserFunction.java | 38 + wiki/parserfunctions/ParserFunctions.java | 70 + wiki/parserfunctions/Plural.java | 51 + wiki/parserfunctions/Switch.java | 77 + wiki/parserfunctions/Tag.java | 67 + wiki/parserfunctions/Time.java | 262 + wiki/parserfunctions/Titleparts.java | 112 + wiki/parserfunctions/expr/ExprParser.java | 729 ++ wiki/tools/Utilities.java | 240 + wiki/tools/WikiFormatter.java | 565 + wiki/tools/WikiPage.java | 118 + wiki/tools/WikiScanner.java | 366 + 88 files changed, 30443 insertions(+) create mode 100644 LICENSE.md create mode 100644 bzip2/BZip2CompressorInputStream.java create mode 100644 bzip2/BZip2Constants.java create mode 100644 bzip2/BitInputStream.java create mode 100644 bzip2/CRC.java create mode 100644 bzip2/CloseShieldFilterInputStream.java create mode 100644 bzip2/CompressorInputStream.java create mode 100644 bzip2/CountingInputStream.java create mode 100644 bzip2/InputStreamStatistics.java create mode 100644 bzip2/Rand.java create mode 100644 info/bliki/extensions/scribunto/ScribuntoException.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/ScribuntoLuaEngine.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/Languages.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwHtml.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwInit.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwInterface.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwLanguage.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwMessage.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwSite.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwText.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwTitle.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwUri.java create mode 100644 info/bliki/extensions/scribunto/engine/lua/interfaces/MwUstring.java create mode 100644 info/bliki/extensions/scribunto/template/Frame.java create mode 100644 info/bliki/wiki/template/dates/PHPDate.java create mode 100644 info/bliki/wiki/template/dates/StringToTime.java create mode 100644 info/bliki/wiki/template/dates/StringToTimeException.java create mode 100644 lib/StringLib.java create mode 100644 lib/luaj-jse-3.0.2p.jar create mode 100644 lib/readme.txt create mode 100644 luabit/bit.lua create mode 100644 luabit/bit32.lua create mode 100644 luabit/hex.lua create mode 100644 luabit/readme.txt create mode 100644 lualib/libraryUtil.lua create mode 100644 lualib/mw.hash.lua create mode 100644 lualib/mw.html.lua create mode 100644 lualib/mw.language.lua create mode 100644 lualib/mw.lua create mode 100644 lualib/mw.message.lua create mode 100644 lualib/mw.site.lua create mode 100644 lualib/mw.text.lua create mode 100644 lualib/mw.title.lua create mode 100644 lualib/mw.uri.lua create mode 100644 lualib/mw.ustring.lua create mode 100644 lualib/mwInit.lua create mode 100644 lualib/package.lua create mode 100644 ustring/README create mode 100644 ustring/charsets.lua create mode 100644 ustring/lower.lua create mode 100644 ustring/normalization-data.lua create mode 100644 ustring/string.lua create mode 100644 ustring/upper.lua create mode 100644 ustring/ustring.lua create mode 100644 wiki.html create mode 100644 wiki/MagicWords.java create mode 100644 wiki/NameSpaces.java create mode 100644 wiki/TemplateParser.java create mode 100644 wiki/TestSuite.java create mode 100644 wiki/WikiFind.java create mode 100644 wiki/WikiSplitter.java create mode 100644 wiki/parserfunctions/Expr.java create mode 100644 wiki/parserfunctions/FormatDate.java create mode 100644 wiki/parserfunctions/Formatnum.java create mode 100644 wiki/parserfunctions/Fullurl.java create mode 100644 wiki/parserfunctions/Fullurle.java create mode 100644 wiki/parserfunctions/If.java create mode 100644 wiki/parserfunctions/Ifeq.java create mode 100644 wiki/parserfunctions/Iferror.java create mode 100644 wiki/parserfunctions/Ifexist.java create mode 100644 wiki/parserfunctions/Ifexpr.java create mode 100644 wiki/parserfunctions/Invoke.java create mode 100644 wiki/parserfunctions/Localurl.java create mode 100644 wiki/parserfunctions/Localurle.java create mode 100644 wiki/parserfunctions/Padleft.java create mode 100644 wiki/parserfunctions/Padright.java create mode 100644 wiki/parserfunctions/ParserFunction.java create mode 100644 wiki/parserfunctions/ParserFunctions.java create mode 100644 wiki/parserfunctions/Plural.java create mode 100644 wiki/parserfunctions/Switch.java create mode 100644 wiki/parserfunctions/Tag.java create mode 100644 wiki/parserfunctions/Time.java create mode 100644 wiki/parserfunctions/Titleparts.java create mode 100644 wiki/parserfunctions/expr/ExprParser.java create mode 100644 wiki/tools/Utilities.java create mode 100644 wiki/tools/WikiFormatter.java create mode 100644 wiki/tools/WikiPage.java create mode 100644 wiki/tools/WikiScanner.java diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..afcec2a --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,67 @@ +License Information, 2023 Livio (javalc6) + +Feel free to modify, re-use this software, please give appropriate +credit by referencing this Github repository. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +IMPORTANT NOTICE +Note that this software is freeware and it is not designed, licensed or +intended for use in mission critical, life support and military purposes. +The use of this software is at the risk of the user. + +DO NOT USE THIS SOFTWARE IF YOU DON'T AGREE WITH STATED CONDITIONS. +==================================================================== +This software includes software from other open source projects, here are related references. + +A) Java lua interpreter luaj: https://github.com/luaj/luaj + +Software is licensed with MIT license +For more information see: +https://github.com/luaj/luaj/blob/master/LICENSE + +B) Wikimedia lua scripts: https://github.com/wikimedia/mediawiki-extensions-Scribunto/tree/master/includes/Engines/LuaCommon + +Software is licensed with GPL-2.0+ and MIT licenses +For more information see: +https://www.mediawiki.org/wiki/Extension:Scribunto + +C) Java scribunto engine: https://github.com/axkr/info.bliki.wikipedia_parser/tree/master/bliki-core/src/main/java/info/bliki/extensions/scribunto + +Software is licensed under the terms of two licenses: + +1) the Eclipse Public License - v 1.0 +http://www.opensource.org/licenses/eclipse-1.0.php +2) the GNU Lesser General Public License - v 2.1 or later +http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html + +For more information see: +https://github.com/axkr/info.bliki.wikipedia_parser/blob/master/licenses.txt + +D) Java strtotime function: https://github.com/axkr/info.bliki.wikipedia_parser/tree/master/bliki-core/src/main/java/info/bliki/wiki/template/dates/ +Software is licensed with following license: + +Copyright (c) 2012 Clutch, Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +For more information see: +https://github.com/collegeman/stringtotime \ No newline at end of file diff --git a/bzip2/BZip2CompressorInputStream.java b/bzip2/BZip2CompressorInputStream.java new file mode 100644 index 0000000..22e61e3 --- /dev/null +++ b/bzip2/BZip2CompressorInputStream.java @@ -0,0 +1,944 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteOrder; +import java.util.Arrays; + +/** + * An input stream that decompresses from the BZip2 format to be read as any other stream. + * + * @NotThreadSafe + */ +public class BZip2CompressorInputStream extends CompressorInputStream + implements BZip2Constants, InputStreamStatistics { + + /** + * Index of the last char in the block, so the block size == last + 1. + */ + private int last; + + /** + * Index in zptr[] of original string after sorting. + */ + private int origPtr; + + /** + * always: in the range 0 .. 9. The current block size is 100000 * this + * number. + */ + private int blockSize100k; + + private boolean blockRandomised; + + private final CRC crc = new CRC(); + + private int nInUse; + + private BitInputStream bin; + private final boolean decompressConcatenated; + + private static final int EOF = 0; + private static final int START_BLOCK_STATE = 1; + private static final int RAND_PART_A_STATE = 2; + private static final int RAND_PART_B_STATE = 3; + private static final int RAND_PART_C_STATE = 4; + private static final int NO_RAND_PART_A_STATE = 5; + private static final int NO_RAND_PART_B_STATE = 6; + private static final int NO_RAND_PART_C_STATE = 7; + + private int currentState = START_BLOCK_STATE; + + private int storedBlockCRC, storedCombinedCRC; + private int computedBlockCRC, computedCombinedCRC; + + // Variables used by setup* methods exclusively + + private int su_count; + private int su_ch2; + private int su_chPrev; + private int su_i2; + private int su_j2; + private int su_rNToGo; + private int su_rTPos; + private int su_tPos; + private char su_z; + + /** + * All memory intensive stuff. This field is initialized by initBlock(). + */ + private BZip2CompressorInputStream.Data data; + + /** + * Constructs a new BZip2CompressorInputStream which decompresses bytes + * read from the specified stream. This doesn't suppprt decompressing + * concatenated .bz2 files. + * + * @param in the InputStream from which this object should be created + * @throws IOException + * if the stream content is malformed or an I/O error occurs. + * @throws NullPointerException + * if {@code in == null} + */ + public BZip2CompressorInputStream(final InputStream in) throws IOException { + this(in, false); + } + + /** + * Constructs a new BZip2CompressorInputStream which decompresses bytes + * read from the specified stream. + * + * @param in the InputStream from which this object should be created + * @param decompressConcatenated + * if true, decompress until the end of the input; + * if false, stop after the first .bz2 stream and + * leave the input position to point to the next + * byte after the .bz2 stream + * + * @throws IOException + * if {@code in == null}, the stream content is malformed, or an I/O error occurs. + */ + public BZip2CompressorInputStream(final InputStream in, final boolean decompressConcatenated) throws IOException { + this.bin = new BitInputStream(in == System.in ? new CloseShieldFilterInputStream(in) : in, + ByteOrder.BIG_ENDIAN); + this.decompressConcatenated = decompressConcatenated; + + init(true); + initBlock(); + } + + @Override + public int read() throws IOException { + if (this.bin != null) { + final int r = read0(); + count(r < 0 ? -1 : 1); + return r; + } + throw new IOException("stream closed"); + } + + /* + * (non-Javadoc) + * + * @see java.io.InputStream#read(byte[], int, int) + */ + @Override + public int read(final byte[] dest, final int offs, final int len) + throws IOException { + if (offs < 0) { + throw new IndexOutOfBoundsException("offs(" + offs + ") < 0."); + } + if (len < 0) { + throw new IndexOutOfBoundsException("len(" + len + ") < 0."); + } + if (offs + len > dest.length) { + throw new IndexOutOfBoundsException("offs(" + offs + ") + len(" + + len + ") > dest.length(" + dest.length + ")."); + } + if (this.bin == null) { + throw new IOException("stream closed"); + } + if (len == 0) { + return 0; + } + + final int hi = offs + len; + int destOffs = offs; + int b; + while (destOffs < hi && ((b = read0()) >= 0)) { + dest[destOffs++] = (byte) b; + count(1); + } + + return (destOffs == offs) ? -1 : (destOffs - offs); + } + + /** + * @since 1.17 + */ + @Override + public long getCompressedCount() { + return bin.getBytesRead(); + } + + private void makeMaps() { + final boolean[] inUse = this.data.inUse; + final byte[] seqToUnseq = this.data.seqToUnseq; + + int nInUseShadow = 0; + + for (int i = 0; i < 256; i++) { + if (inUse[i]) { + seqToUnseq[nInUseShadow++] = (byte) i; + } + } + + this.nInUse = nInUseShadow; + } + + private int read0() throws IOException { + switch (currentState) { + case EOF: + return -1; + + case START_BLOCK_STATE: + return setupBlock(); + + case RAND_PART_A_STATE: + throw new IllegalStateException(); + + case RAND_PART_B_STATE: + return setupRandPartB(); + + case RAND_PART_C_STATE: + return setupRandPartC(); + + case NO_RAND_PART_A_STATE: + throw new IllegalStateException(); + + case NO_RAND_PART_B_STATE: + return setupNoRandPartB(); + + case NO_RAND_PART_C_STATE: + return setupNoRandPartC(); + + default: + throw new IllegalStateException(); + } + } + + private int readNextByte(BitInputStream in) throws IOException { + long b = in.readBits(8); + return (int) b; + } + + private boolean init(final boolean isFirstStream) throws IOException { + if (null == bin) { + throw new IOException("No InputStream"); + } + + if (!isFirstStream) { + bin.clearBitCache(); + } + + final int magic0 = readNextByte(this.bin); + if (magic0 == -1 && !isFirstStream) { + return false; + } + final int magic1 = readNextByte(this.bin); + final int magic2 = readNextByte(this.bin); + + if (magic0 != 'B' || magic1 != 'Z' || magic2 != 'h') { + throw new IOException(isFirstStream + ? "Stream is not in the BZip2 format" + : "Garbage after a valid BZip2 stream"); + } + + final int blockSize = readNextByte(this.bin); + if ((blockSize < '1') || (blockSize > '9')) { + throw new IOException("BZip2 block size is invalid"); + } + + this.blockSize100k = blockSize - '0'; + + this.computedCombinedCRC = 0; + + return true; + } + + private void initBlock() throws IOException { + BitInputStream bin = this.bin; + char magic0; + char magic1; + char magic2; + char magic3; + char magic4; + char magic5; + + while (true) { + // Get the block magic bytes. + magic0 = bsGetUByte(bin); + magic1 = bsGetUByte(bin); + magic2 = bsGetUByte(bin); + magic3 = bsGetUByte(bin); + magic4 = bsGetUByte(bin); + magic5 = bsGetUByte(bin); + + // If isn't end of stream magic, break out of the loop. + if (magic0 != 0x17 || magic1 != 0x72 || magic2 != 0x45 + || magic3 != 0x38 || magic4 != 0x50 || magic5 != 0x90) { + break; + } + + // End of stream was reached. Check the combined CRC and + // advance to the next .bz2 stream if decoding concatenated + // streams. + if (complete()) { + return; + } + } + + if (magic0 != 0x31 || // '1' + magic1 != 0x41 || // ')' + magic2 != 0x59 || // 'Y' + magic3 != 0x26 || // '&' + magic4 != 0x53 || // 'S' + magic5 != 0x59 // 'Y' + ) { + this.currentState = EOF; + throw new IOException("bad block header"); + } + this.storedBlockCRC = bsGetInt(bin); + this.blockRandomised = bsR(bin, 1) == 1; + + /** + * Allocate data here instead in constructor, so we do not allocate + * it if the input file is empty. + */ + if (this.data == null) { + this.data = new Data(this.blockSize100k); + } + + // currBlockNo++; + getAndMoveToFrontDecode(); + + this.crc.initialiseCRC(); + this.currentState = START_BLOCK_STATE; + } + + private void endBlock() throws IOException { + this.computedBlockCRC = this.crc.getFinalCRC(); + + // A bad CRC is considered a fatal error. + if (this.storedBlockCRC != this.computedBlockCRC) { + // make next blocks readable without error + // (repair feature, not yet documented, not tested) + this.computedCombinedCRC = (this.storedCombinedCRC << 1) + | (this.storedCombinedCRC >>> 31); + this.computedCombinedCRC ^= this.storedBlockCRC; + + throw new IOException("BZip2 CRC error"); + } + + this.computedCombinedCRC = (this.computedCombinedCRC << 1) + | (this.computedCombinedCRC >>> 31); + this.computedCombinedCRC ^= this.computedBlockCRC; + } + + private boolean complete() throws IOException { + this.storedCombinedCRC = bsGetInt(bin); + this.currentState = EOF; + this.data = null; + + if (this.storedCombinedCRC != this.computedCombinedCRC) { + throw new IOException("BZip2 CRC error"); + } + + // Look for the next .bz2 stream if decompressing + // concatenated files. + return !decompressConcatenated || !init(false); + } + + @Override + public void close() throws IOException { + final BitInputStream inShadow = this.bin; + if (inShadow != null) { + try { + inShadow.close(); + } finally { + this.data = null; + this.bin = null; + } + } + } + + /** + * read bits from the input stream + * @param n the number of bits to read, must not exceed 32? + * @return the requested bits combined into an int + * @throws IOException + */ + private static int bsR(BitInputStream bin, final int n) throws IOException { + long thech = bin.readBits(n); + if (thech < 0) { + throw new IOException("unexpected end of stream"); + } + return (int) thech; + } + + private static boolean bsGetBit(BitInputStream bin) throws IOException { + return bsR(bin, 1) != 0; + } + + private static char bsGetUByte(BitInputStream bin) throws IOException { + return (char) bsR(bin, 8); + } + + private static int bsGetInt(BitInputStream bin) throws IOException { + return bsR(bin, 32); + } + + private static void checkBounds(final int checkVal, final int limitExclusive, String name) + throws IOException { + if (checkVal < 0) { + throw new IOException("Corrupted input, " + name + " value negative"); + } + if (checkVal >= limitExclusive) { + throw new IOException("Corrupted input, " + name + " value too big"); + } + } + + /** + * Called by createHuffmanDecodingTables() exclusively. + */ + private static void hbCreateDecodeTables(final int[] limit, + final int[] base, final int[] perm, final char[] length, + final int minLen, final int maxLen, final int alphaSize) + throws IOException { + for (int i = minLen, pp = 0; i <= maxLen; i++) { + for (int j = 0; j < alphaSize; j++) { + if (length[j] == i) { + perm[pp++] = j; + } + } + } + + for (int i = MAX_CODE_LEN; --i > 0;) { + base[i] = 0; + limit[i] = 0; + } + + for (int i = 0; i < alphaSize; i++) { + final int l = length[i]; + checkBounds(l, MAX_ALPHA_SIZE, "length"); + base[l + 1]++; + } + + for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) { + b += base[i]; + base[i] = b; + } + + for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) { + final int nb = base[i + 1]; + vec += nb - b; + b = nb; + limit[i] = vec - 1; + vec <<= 1; + } + + for (int i = minLen + 1; i <= maxLen; i++) { + base[i] = ((limit[i - 1] + 1) << 1) - base[i]; + } + } + + private void recvDecodingTables() throws IOException { + final BitInputStream bin = this.bin; + final Data dataShadow = this.data; + final boolean[] inUse = dataShadow.inUse; + final byte[] pos = dataShadow.recvDecodingTables_pos; + final byte[] selector = dataShadow.selector; + final byte[] selectorMtf = dataShadow.selectorMtf; + + int inUse16 = 0; + + /* Receive the mapping table */ + for (int i = 0; i < 16; i++) { + if (bsGetBit(bin)) { + inUse16 |= 1 << i; + } + } + + Arrays.fill(inUse, false); + for (int i = 0; i < 16; i++) { + if ((inUse16 & (1 << i)) != 0) { + final int i16 = i << 4; + for (int j = 0; j < 16; j++) { + if (bsGetBit(bin)) { + inUse[i16 + j] = true; + } + } + } + } + + makeMaps(); + final int alphaSize = this.nInUse + 2; + /* Now the selectors */ + final int nGroups = bsR(bin, 3); + final int nSelectors = bsR(bin, 15); + checkBounds(alphaSize, MAX_ALPHA_SIZE + 1, "alphaSize"); + checkBounds(nGroups, N_GROUPS + 1, "nGroups"); + checkBounds(nSelectors, MAX_SELECTORS + 1, "nSelectors"); + + for (int i = 0; i < nSelectors; i++) { + int j = 0; + while (bsGetBit(bin)) { + j++; + } + selectorMtf[i] = (byte) j; + } + + /* Undo the MTF values for the selectors. */ + for (int v = nGroups; --v >= 0;) { + pos[v] = (byte) v; + } + + for (int i = 0; i < nSelectors; i++) { + int v = selectorMtf[i] & 0xff; + checkBounds(v, N_GROUPS, "selectorMtf"); + final byte tmp = pos[v]; + while (v > 0) { + // nearly all times v is zero, 4 in most other cases + pos[v] = pos[v - 1]; + v--; + } + pos[0] = tmp; + selector[i] = tmp; + } + + final char[][] len = dataShadow.temp_charArray2d; + + /* Now the coding tables */ + for (int t = 0; t < nGroups; t++) { + int curr = bsR(bin, 5); + final char[] len_t = len[t]; + for (int i = 0; i < alphaSize; i++) { + while (bsGetBit(bin)) { + curr += bsGetBit(bin) ? -1 : 1; + } + len_t[i] = (char) curr; + } + } + + // finally create the Huffman tables + createHuffmanDecodingTables(alphaSize, nGroups); + } + + /** + * Called by recvDecodingTables() exclusively. + */ + private void createHuffmanDecodingTables(final int alphaSize, + final int nGroups) throws IOException { + final Data dataShadow = this.data; + final char[][] len = dataShadow.temp_charArray2d; + final int[] minLens = dataShadow.minLens; + final int[][] limit = dataShadow.limit; + final int[][] base = dataShadow.base; + final int[][] perm = dataShadow.perm; + + for (int t = 0; t < nGroups; t++) { + int minLen = 32; + int maxLen = 0; + final char[] len_t = len[t]; + for (int i = alphaSize; --i >= 0;) { + final char lent = len_t[i]; + if (lent > maxLen) { + maxLen = lent; + } + if (lent < minLen) { + minLen = lent; + } + } + hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen, + maxLen, alphaSize); + minLens[t] = minLen; + } + } + + private void getAndMoveToFrontDecode() throws IOException { + final BitInputStream bin = this.bin; + this.origPtr = bsR(bin, 24); + recvDecodingTables(); + + final Data dataShadow = this.data; + final byte[] ll8 = dataShadow.ll8; + final int[] unzftab = dataShadow.unzftab; + final byte[] selector = dataShadow.selector; + final byte[] seqToUnseq = dataShadow.seqToUnseq; + final char[] yy = dataShadow.getAndMoveToFrontDecode_yy; + final int[] minLens = dataShadow.minLens; + final int[][] limit = dataShadow.limit; + final int[][] base = dataShadow.base; + final int[][] perm = dataShadow.perm; + final int limitLast = this.blockSize100k * 100000; + + /* + * Setting up the unzftab entries here is not strictly necessary, but it + * does save having to do it later in a separate pass, and so saves a + * block's worth of cache misses. + */ + for (int i = 256; --i >= 0;) { + yy[i] = (char) i; + unzftab[i] = 0; + } + + int groupNo = 0; + int groupPos = G_SIZE - 1; + final int eob = this.nInUse + 1; + int nextSym = getAndMoveToFrontDecode0(); + int lastShadow = -1; + int zt = selector[groupNo] & 0xff; + checkBounds(zt, N_GROUPS, "zt"); + int[] base_zt = base[zt]; + int[] limit_zt = limit[zt]; + int[] perm_zt = perm[zt]; + int minLens_zt = minLens[zt]; + + while (nextSym != eob) { + if ((nextSym == RUNA) || (nextSym == RUNB)) { + int s = -1; + + for (int n = 1; true; n <<= 1) { + if (nextSym == RUNA) { + s += n; + } else if (nextSym == RUNB) { + s += n << 1; + } else { + break; + } + + if (groupPos == 0) { + groupPos = G_SIZE - 1; + checkBounds(++groupNo, MAX_SELECTORS, "groupNo"); + zt = selector[groupNo] & 0xff; + checkBounds(zt, N_GROUPS, "zt"); + base_zt = base[zt]; + limit_zt = limit[zt]; + perm_zt = perm[zt]; + minLens_zt = minLens[zt]; + } else { + groupPos--; + } + + int zn = minLens_zt; + checkBounds(zn, MAX_ALPHA_SIZE, "zn"); + int zvec = bsR(bin, zn); + while(zvec > limit_zt[zn]) { + checkBounds(++zn, MAX_ALPHA_SIZE, "zn"); + zvec = (zvec << 1) | bsR(bin, 1); + } + final int tmp = zvec - base_zt[zn]; + checkBounds(tmp, MAX_ALPHA_SIZE, "zvec"); + nextSym = perm_zt[tmp]; + } + + final int yy0 = yy[0]; + checkBounds(yy0, 256, "yy"); + final byte ch = seqToUnseq[yy0]; + unzftab[ch & 0xff] += s + 1; + + final int from = ++lastShadow; + lastShadow += s; + Arrays.fill(ll8, from, lastShadow + 1, ch); + + if (lastShadow >= limitLast) { + throw new IOException("block overrun while expanding RLE in MTF, " + + lastShadow + " exceeds " + limitLast); + } + } else { + if (++lastShadow >= limitLast) { + throw new IOException("block overrun in MTF, " + + lastShadow + " exceeds " + limitLast); + } + checkBounds(nextSym, 256 + 1, "nextSym"); + + final char tmp = yy[nextSym - 1]; + checkBounds(tmp, 256, "yy"); + unzftab[seqToUnseq[tmp] & 0xff]++; + ll8[lastShadow] = seqToUnseq[tmp]; + + /* + * This loop is hammered during decompression, hence avoid + * native method call overhead of System.arraycopy for very + * small ranges to copy. + */ + if (nextSym <= 16) { + for (int j = nextSym - 1; j > 0;) { + yy[j] = yy[--j]; + } + } else { + System.arraycopy(yy, 0, yy, 1, nextSym - 1); + } + + yy[0] = tmp; + + if (groupPos == 0) { + groupPos = G_SIZE - 1; + checkBounds(++groupNo, MAX_SELECTORS, "groupNo"); + zt = selector[groupNo] & 0xff; + checkBounds(zt, N_GROUPS, "zt"); + base_zt = base[zt]; + limit_zt = limit[zt]; + perm_zt = perm[zt]; + minLens_zt = minLens[zt]; + } else { + groupPos--; + } + + int zn = minLens_zt; + checkBounds(zn, MAX_ALPHA_SIZE, "zn"); + int zvec = bsR(bin, zn); + while(zvec > limit_zt[zn]) { + checkBounds(++zn, MAX_ALPHA_SIZE, "zn"); + zvec = (zvec << 1) | bsR(bin, 1); + } + final int idx = zvec - base_zt[zn]; + checkBounds(idx, MAX_ALPHA_SIZE, "zvec"); + nextSym = perm_zt[idx]; + } + } + + this.last = lastShadow; + } + + private int getAndMoveToFrontDecode0() throws IOException { + final Data dataShadow = this.data; + final int zt = dataShadow.selector[0] & 0xff; + checkBounds(zt, N_GROUPS, "zt"); + final int[] limit_zt = dataShadow.limit[zt]; + int zn = dataShadow.minLens[zt]; + checkBounds(zn, MAX_ALPHA_SIZE, "zn"); + int zvec = bsR(bin, zn); + while (zvec > limit_zt[zn]) { + checkBounds(++zn, MAX_ALPHA_SIZE, "zn"); + zvec = (zvec << 1) | bsR(bin, 1); + } + final int tmp = zvec - dataShadow.base[zt][zn]; + checkBounds(tmp, MAX_ALPHA_SIZE, "zvec"); + + return dataShadow.perm[zt][tmp]; + } + + private int setupBlock() throws IOException { + if (currentState == EOF || this.data == null) { + return -1; + } + + final int[] cftab = this.data.cftab; + final int ttLen = this.last + 1; + final int[] tt = this.data.initTT(ttLen); + final byte[] ll8 = this.data.ll8; + cftab[0] = 0; + System.arraycopy(this.data.unzftab, 0, cftab, 1, 256); + + for (int i = 1, c = cftab[0]; i <= 256; i++) { + c += cftab[i]; + cftab[i] = c; + } + + for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) { + final int tmp = cftab[ll8[i] & 0xff]++; + checkBounds(tmp, ttLen, "tt index"); + tt[tmp] = i; + } + + if ((this.origPtr < 0) || (this.origPtr >= tt.length)) { + throw new IOException("stream corrupted"); + } + + this.su_tPos = tt[this.origPtr]; + this.su_count = 0; + this.su_i2 = 0; + this.su_ch2 = 256; /* not a char and not EOF */ + + if (this.blockRandomised) { + this.su_rNToGo = 0; + this.su_rTPos = 0; + return setupRandPartA(); + } + return setupNoRandPartA(); + } + + private int setupRandPartA() throws IOException { + if (this.su_i2 <= this.last) { + this.su_chPrev = this.su_ch2; + int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; + checkBounds(this.su_tPos, this.data.tt.length, "su_tPos"); + this.su_tPos = this.data.tt[this.su_tPos]; + if (this.su_rNToGo == 0) { + this.su_rNToGo = Rand.rNums(this.su_rTPos) - 1; + if (++this.su_rTPos == 512) { + this.su_rTPos = 0; + } + } else { + this.su_rNToGo--; + } + this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0; + this.su_i2++; + this.currentState = RAND_PART_B_STATE; + this.crc.updateCRC(su_ch2Shadow); + return su_ch2Shadow; + } + endBlock(); + initBlock(); + return setupBlock(); + } + + private int setupNoRandPartA() throws IOException { + if (this.su_i2 <= this.last) { + this.su_chPrev = this.su_ch2; + final int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff; + this.su_ch2 = su_ch2Shadow; + checkBounds(this.su_tPos, this.data.tt.length, "su_tPos"); + this.su_tPos = this.data.tt[this.su_tPos]; + this.su_i2++; + this.currentState = NO_RAND_PART_B_STATE; + this.crc.updateCRC(su_ch2Shadow); + return su_ch2Shadow; + } + this.currentState = NO_RAND_PART_A_STATE; + endBlock(); + initBlock(); + return setupBlock(); + } + + private int setupRandPartB() throws IOException { + if (this.su_ch2 != this.su_chPrev) { + this.currentState = RAND_PART_A_STATE; + this.su_count = 1; + return setupRandPartA(); + } else if (++this.su_count >= 4) { + this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); + checkBounds(this.su_tPos, this.data.tt.length, "su_tPos"); + this.su_tPos = this.data.tt[this.su_tPos]; + if (this.su_rNToGo == 0) { + this.su_rNToGo = Rand.rNums(this.su_rTPos) - 1; + if (++this.su_rTPos == 512) { + this.su_rTPos = 0; + } + } else { + this.su_rNToGo--; + } + this.su_j2 = 0; + this.currentState = RAND_PART_C_STATE; + if (this.su_rNToGo == 1) { + this.su_z ^= 1; + } + return setupRandPartC(); + } else { + this.currentState = RAND_PART_A_STATE; + return setupRandPartA(); + } + } + + private int setupRandPartC() throws IOException { + if (this.su_j2 < this.su_z) { + this.crc.updateCRC(this.su_ch2); + this.su_j2++; + return this.su_ch2; + } + this.currentState = RAND_PART_A_STATE; + this.su_i2++; + this.su_count = 0; + return setupRandPartA(); + } + + private int setupNoRandPartB() throws IOException { + if (this.su_ch2 != this.su_chPrev) { + this.su_count = 1; + return setupNoRandPartA(); + } else if (++this.su_count >= 4) { + checkBounds(this.su_tPos, this.data.ll8.length, "su_tPos"); + this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff); + this.su_tPos = this.data.tt[this.su_tPos]; + this.su_j2 = 0; + return setupNoRandPartC(); + } else { + return setupNoRandPartA(); + } + } + + private int setupNoRandPartC() throws IOException { + if (this.su_j2 < this.su_z) { + final int su_ch2Shadow = this.su_ch2; + this.crc.updateCRC(su_ch2Shadow); + this.su_j2++; + this.currentState = NO_RAND_PART_C_STATE; + return su_ch2Shadow; + } + this.su_i2++; + this.su_count = 0; + return setupNoRandPartA(); + } + + private static final class Data { + + // (with blockSize 900k) + final boolean[] inUse = new boolean[256]; // 256 byte + + final byte[] seqToUnseq = new byte[256]; // 256 byte + final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte + final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte + + /** + * Freq table collected to save a pass over the data during + * decompression. + */ + final int[] unzftab = new int[256]; // 1024 byte + + final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte + final int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte + final int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte + final int[] minLens = new int[N_GROUPS]; // 24 byte + + final int[] cftab = new int[257]; // 1028 byte + final char[] getAndMoveToFrontDecode_yy = new char[256]; // 512 byte + final char[][] temp_charArray2d = new char[N_GROUPS][MAX_ALPHA_SIZE]; // 3096 + // byte + final byte[] recvDecodingTables_pos = new byte[N_GROUPS]; // 6 byte + // --------------- + // 60798 byte + + int[] tt; // 3600000 byte + byte[] ll8; // 900000 byte + + // --------------- + // 4560782 byte + // =============== + + Data(final int blockSize100k) { + this.ll8 = new byte[blockSize100k * BZip2Constants.BASEBLOCKSIZE]; + } + + /** + * Initializes the {@link #tt} array. + * + * This method is called when the required length of the array is known. + * I don't initialize it at construction time to avoid unneccessary + * memory allocation when compressing small files. + */ + int[] initTT(final int length) { + int[] ttShadow = this.tt; + + // tt.length should always be >= length, but theoretically + // it can happen, if the compressor mixed small and large + // blocks. Normally only the last block will be smaller + // than others. + if ((ttShadow == null) || (ttShadow.length < length)) { + this.tt = ttShadow = new int[length]; + } + + return ttShadow; + } + + } + + /** + * Checks if the signature matches what is expected for a bzip2 file. + * + * @param signature + * the bytes to check + * @param length + * the number of bytes to check + * @return true, if this stream is a bzip2 compressed stream, false otherwise + * + * @since 1.1 + */ + public static boolean matches(final byte[] signature, final int length) { + return length >= 3 && signature[0] == 'B' && + signature[1] == 'Z' && signature[2] == 'h'; + } +} diff --git a/bzip2/BZip2Constants.java b/bzip2/BZip2Constants.java new file mode 100644 index 0000000..d2e60bf --- /dev/null +++ b/bzip2/BZip2Constants.java @@ -0,0 +1,22 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ + +/** + * Constants for both the compress and decompress BZip2 classes. + */ +interface BZip2Constants { + + int BASEBLOCKSIZE = 100000; + int MAX_ALPHA_SIZE = 258; + int MAX_CODE_LEN = 23; + int RUNA = 0; + int RUNB = 1; + int N_GROUPS = 6; + int G_SIZE = 50; + int N_ITERS = 4; + int MAX_SELECTORS = (2 + (900000 / G_SIZE)); + int NUM_OVERSHOOT_BYTES = 20; + +} \ No newline at end of file diff --git a/bzip2/BitInputStream.java b/bzip2/BitInputStream.java new file mode 100644 index 0000000..c84f6b5 --- /dev/null +++ b/bzip2/BitInputStream.java @@ -0,0 +1,187 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteOrder; + +/** + * Reads bits from an InputStream. + * @since 1.10 + * @NotThreadSafe + */ +public class BitInputStream implements Closeable { + private static final int MAXIMUM_CACHE_SIZE = 63; // bits in long minus sign bit + private static final long[] MASKS = new long[MAXIMUM_CACHE_SIZE + 1]; + + static { + for (int i = 1; i <= MAXIMUM_CACHE_SIZE; i++) { + MASKS[i] = (MASKS[i - 1] << 1) + 1; + } + } + + private final CountingInputStream in; + private final ByteOrder byteOrder; + private long bitsCached = 0; + private int bitsCachedSize = 0; + + /** + * Constructor taking an InputStream and its bit arrangement. + * @param in the InputStream + * @param byteOrder the bit arrangement across byte boundaries, + * either BIG_ENDIAN (aaaaabbb bb000000) or LITTLE_ENDIAN (bbbaaaaa 000000bb) + */ + public BitInputStream(final InputStream in, final ByteOrder byteOrder) { + this.in = new CountingInputStream(in); + this.byteOrder = byteOrder; + } + + @Override + public void close() throws IOException { + in.close(); + } + + /** + * Clears the cache of bits that have been read from the + * underlying stream but not yet provided via {@link #readBits}. + */ + public void clearBitCache() { + bitsCached = 0; + bitsCachedSize = 0; + } + + /** + * Returns at most 63 bits read from the underlying stream. + * + * @param count the number of bits to read, must be a positive + * number not bigger than 63. + * @return the bits concatenated as a long using the stream's byte order. + * -1 if the end of the underlying stream has been reached before reading + * the requested number of bits + * @throws IOException on error + */ + public long readBits(final int count) throws IOException { + if (count < 0 || count > MAXIMUM_CACHE_SIZE) { + throw new IllegalArgumentException("count must not be negative or greater than " + MAXIMUM_CACHE_SIZE); + } + if (ensureCache(count)) { + return -1; + } + + if (bitsCachedSize < count) { + return processBitsGreater57(count); + } + return readCachedBits(count); + } + + /** + * Returns the number of bits that can be read from this input + * stream without reading from the underlying input stream at all. + * @return estimate of the number of bits that can be read without reading from the underlying stream + * @since 1.16 + */ + public int bitsCached() { + return bitsCachedSize; + } + + /** + * Returns an estimate of the number of bits that can be read from + * this input stream without blocking by the next invocation of a + * method for this input stream. + * @throws IOException if the underlying stream throws one when calling available + * @return estimate of the number of bits that can be read without blocking + * @since 1.16 + */ + public long bitsAvailable() throws IOException { + return bitsCachedSize + ((long) Byte.SIZE) * in.available(); + } + + /** + * Drops bits until the next bits will be read from a byte boundary. + * @since 1.16 + */ + public void alignWithByteBoundary() { + int toSkip = bitsCachedSize % Byte.SIZE; + if (toSkip > 0) { + readCachedBits(toSkip); + } + } + + /** + * Returns the number of bytes read from the underlying stream. + * + *
This includes the bytes read to fill the current cache and + * not read as bits so far.
+ * @return the number of bytes read from the underlying stream + * @since 1.17 + */ + public long getBytesRead() { + return in.getBytesRead(); + } + + private long processBitsGreater57(final int count) throws IOException { + final long bitsOut; + int overflowBits = 0; + long overflow = 0L; + + // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow + int bitsToAddCount = count - bitsCachedSize; + overflowBits = Byte.SIZE - bitsToAddCount; + final long nextByte = in.read(); + if (nextByte < 0) { + return nextByte; + } + if (byteOrder == ByteOrder.LITTLE_ENDIAN) { + long bitsToAdd = nextByte & MASKS[bitsToAddCount]; + bitsCached |= (bitsToAdd << bitsCachedSize); + overflow = (nextByte >>> bitsToAddCount) & MASKS[overflowBits]; + } else { + bitsCached <<= bitsToAddCount; + long bitsToAdd = (nextByte >>> (overflowBits)) & MASKS[bitsToAddCount]; + bitsCached |= bitsToAdd; + overflow = nextByte & MASKS[overflowBits]; + } + bitsOut = bitsCached & MASKS[count]; + bitsCached = overflow; + bitsCachedSize = overflowBits; + return bitsOut; + } + + private long readCachedBits(int count) { + final long bitsOut; + if (byteOrder == ByteOrder.LITTLE_ENDIAN) { + bitsOut = (bitsCached & MASKS[count]); + bitsCached >>>= count; + } else { + bitsOut = (bitsCached >> (bitsCachedSize - count)) & MASKS[count]; + } + bitsCachedSize -= count; + return bitsOut; + } + + /** + * Fills the cache up to 56 bits + * @param count + * @return return true, when EOF + * @throws IOException + */ + private boolean ensureCache(final int count) throws IOException { + while (bitsCachedSize < count && bitsCachedSize < 57) { + final long nextByte = in.read(); + if (nextByte < 0) { + return true; + } + if (byteOrder == ByteOrder.LITTLE_ENDIAN) { + bitsCached |= (nextByte << bitsCachedSize); + } else { + bitsCached <<= Byte.SIZE; + bitsCached |= nextByte; + } + bitsCachedSize += Byte.SIZE; + } + return false; + } + +} diff --git a/bzip2/CRC.java b/bzip2/CRC.java new file mode 100644 index 0000000..8d1d5a3 --- /dev/null +++ b/bzip2/CRC.java @@ -0,0 +1,114 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ + +class CRC { + private static final int crc32Table[] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, + 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, + 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, + 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, + 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, + 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, + 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, + 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, + 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, + 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, + 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, + 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, + 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, + 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, + 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, + 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, + 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, + 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 + }; + + CRC() { + initialiseCRC(); + } + + void initialiseCRC() { + globalCrc = 0xffffffff; + } + + int getFinalCRC() { + return ~globalCrc; + } + + int getGlobalCRC() { + return globalCrc; + } + + void setGlobalCRC(final int newCrc) { + globalCrc = newCrc; + } + + void updateCRC(final int inCh) { + int temp = (globalCrc >> 24) ^ inCh; + if (temp < 0) { + temp = 256 + temp; + } + globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp]; + } + + void updateCRC(final int inCh, int repeat) { + int globalCrcShadow = this.globalCrc; + while (repeat-- > 0) { + final int temp = (globalCrcShadow >> 24) ^ inCh; + globalCrcShadow = (globalCrcShadow << 8) ^ crc32Table[(temp >= 0) + ? temp + : (temp + 256)]; + } + this.globalCrc = globalCrcShadow; + } + + private int globalCrc; +} \ No newline at end of file diff --git a/bzip2/CloseShieldFilterInputStream.java b/bzip2/CloseShieldFilterInputStream.java new file mode 100644 index 0000000..4c20f7e --- /dev/null +++ b/bzip2/CloseShieldFilterInputStream.java @@ -0,0 +1,25 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Re-implements {@link FilterInputStream#close()} to do nothing. + * @since 1.14 + */ +public class CloseShieldFilterInputStream extends FilterInputStream { + + public CloseShieldFilterInputStream(InputStream in) { + super(in); + } + + @Override + public void close() throws IOException { + // NO IMPLEMENTATION. + } + +} diff --git a/bzip2/CompressorInputStream.java b/bzip2/CompressorInputStream.java new file mode 100644 index 0000000..4ab9428 --- /dev/null +++ b/bzip2/CompressorInputStream.java @@ -0,0 +1,81 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ + +import java.io.InputStream; + +public abstract class CompressorInputStream extends InputStream { + private long bytesRead = 0; + + /** + * Increments the counter of already read bytes. + * Doesn't increment if the EOF has been hit (read == -1) + * + * @param read the number of bytes read + * + * @since 1.1 + */ + protected void count(final int read) { + count((long) read); + } + + /** + * Increments the counter of already read bytes. + * Doesn't increment if the EOF has been hit (read == -1) + * + * @param read the number of bytes read + */ + protected void count(final long read) { + if (read != -1) { + bytesRead = bytesRead + read; + } + } + + /** + * Decrements the counter of already read bytes. + * + * @param pushedBack the number of bytes pushed back. + * @since 1.7 + */ + protected void pushedBackBytes(final long pushedBack) { + bytesRead -= pushedBack; + } + + /** + * Returns the current number of bytes read from this stream. + * @return the number of read bytes + * @deprecated this method may yield wrong results for large + * archives, use #getBytesRead instead + */ + @Deprecated + public int getCount() { + return (int) bytesRead; + } + + /** + * Returns the current number of bytes read from this stream. + * @return the number of read bytes + * + * @since 1.1 + */ + public long getBytesRead() { + return bytesRead; + } + + /** + * Returns the amount of raw or compressed bytes read by the stream. + * + *This implementation invokes {@link #getBytesRead}.
+ * + *Provides half of {@link + * org.apache.commons.compress.utils.InputStreamStatistics} + * without forcing subclasses to implement the other half.
+ * + * @return the amount of decompressed bytes returned by the stream + * @since 1.17 + */ + public long getUncompressedCount() { + return getBytesRead(); + } +} diff --git a/bzip2/CountingInputStream.java b/bzip2/CountingInputStream.java new file mode 100644 index 0000000..0b531f5 --- /dev/null +++ b/bzip2/CountingInputStream.java @@ -0,0 +1,61 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Stream that tracks the number of bytes read. + * @since 1.3 + * @NotThreadSafe + */ +public class CountingInputStream extends FilterInputStream { + private long bytesRead; + + public CountingInputStream(final InputStream in) { + super(in); + } + + @Override + public int read() throws IOException { + final int r = in.read(); + if (r >= 0) { + count(1); + } + return r; + } + @Override + public int read(final byte[] b) throws IOException { + return read(b, 0, b.length); + } + @Override + public int read(final byte[] b, final int off, final int len) throws IOException { + final int r = in.read(b, off, len); + if (r >= 0) { + count(r); + } + return r; + } + /** + * Increments the counter of already read bytes. + * Doesn't increment if the EOF has been hit (read == -1) + * + * @param read the number of bytes read + */ + protected final void count(final long read) { + if (read != -1) { + bytesRead += read; + } + } + + /** + * Returns the current number of bytes read from this stream. + * @return the number of read bytes + */ + public long getBytesRead() { + return bytesRead; + } +} diff --git a/bzip2/InputStreamStatistics.java b/bzip2/InputStreamStatistics.java new file mode 100644 index 0000000..c1ff9e9 --- /dev/null +++ b/bzip2/InputStreamStatistics.java @@ -0,0 +1,16 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ + +public interface InputStreamStatistics { + /** + * @return the amount of raw or compressed bytes read by the stream + */ + long getCompressedCount(); + + /** + * @return the amount of decompressed bytes returned by the stream + */ + long getUncompressedCount(); +} diff --git a/bzip2/Rand.java b/bzip2/Rand.java new file mode 100644 index 0000000..8246ae0 --- /dev/null +++ b/bzip2/Rand.java @@ -0,0 +1,74 @@ +package bzip2; +/* included in https://commons.apache.org/proper/commons-compress + reused under Apache License version 2.0 +*/ +/** + * Random numbers for both the compress and decompress BZip2 classes. + */ +final class Rand { + + private static final int[] RNUMS = { + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 + }; + + /** + * Return the random number at a specific index. + * + * @param i the index + * @return the random number + */ + static int rNums(final int i){ + return RNUMS[i]; + } +} \ No newline at end of file diff --git a/info/bliki/extensions/scribunto/ScribuntoException.java b/info/bliki/extensions/scribunto/ScribuntoException.java new file mode 100644 index 0000000..643c4ef --- /dev/null +++ b/info/bliki/extensions/scribunto/ScribuntoException.java @@ -0,0 +1,11 @@ +package info.bliki.extensions.scribunto; + +public final class ScribuntoException extends Exception { + public ScribuntoException(Exception e) { + super(e); + } + + public ScribuntoException(String s) { + super(s); + } +} diff --git a/info/bliki/extensions/scribunto/engine/lua/ScribuntoLuaEngine.java b/info/bliki/extensions/scribunto/engine/lua/ScribuntoLuaEngine.java new file mode 100644 index 0000000..491cd78 --- /dev/null +++ b/info/bliki/extensions/scribunto/engine/lua/ScribuntoLuaEngine.java @@ -0,0 +1,647 @@ +/* Scribunto interface with Luaj based on Axel Kramer Scribunto engine: https://github.com/axkr/info.bliki.wikipedia_parser/tree/master/bliki-core/src/main/java/info/bliki/extensions/scribunto + +references: +https://www.mediawiki.org/wiki/Extension:Scribunto +https://www.mediawiki.org/wiki/Extension:Scribunto/Lua_reference_manual + +php & lua code: +https://github.com/wikimedia/mediawiki-extensions-Scribunto/tree/master/includes/Engines/LuaCommon + +*/ +package info.bliki.extensions.scribunto.engine.lua; + +import info.bliki.extensions.scribunto.ScribuntoException; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwHtml; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwInit; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwInterface; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwLanguage; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwMessage; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwSite; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwText; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwTitle; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwUri; +import info.bliki.extensions.scribunto.engine.lua.interfaces.MwUstring; +import info.bliki.extensions.scribunto.template.Frame; + +import org.luaj.vm2.Globals; +import org.luaj.vm2.LuaClosure; +import org.luaj.vm2.LuaError; +import org.luaj.vm2.LuaFunction; +import org.luaj.vm2.LuaString; +import org.luaj.vm2.LuaTable; +import org.luaj.vm2.LuaValue; +import org.luaj.vm2.Prototype; +import org.luaj.vm2.Varargs; +import org.luaj.vm2.lib.OneArgFunction; +import org.luaj.vm2.lib.ResourceFinder; +import org.luaj.vm2.lib.ThreeArgFunction; +import org.luaj.vm2.lib.TwoArgFunction; +import org.luaj.vm2.lib.VarArgFunction; +import org.luaj.vm2.lib.ZeroArgFunction; +import org.luaj.vm2.lib.jse.JsePlatform; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import wiki.parserfunctions.ParserFunction; +import wiki.parserfunctions.ParserFunctions; +import wiki.MagicWords; +import wiki.tools.WikiPage; + +public final class ScribuntoLuaEngine implements MwInterface { + private static final int MAX_EXPENSIVE_CALLS = 10; + private static final boolean ENABLE_LUA_DEBUG_LIBRARY = false; + private final Globals globals; + private Frame currentFrame; + private final Map
+ * There are two ways to use StringToTime
to parse dates:
+ *
StringToTime
with
+ * {@link #StringToTime(Object)}
+ * The static methods provide a UNIX-style timestamp, a {@link Date}
+ * instance, or a {@link Calendar} instance. In the event the time
+ * expression provided is invalid, these methods return
+ * Boolean.FALSE
.
+ *
+ * Instances of StringToTime
inherit from {@link Date};
+ * so, when instantiated with an expression that the algorithm recognizes, the
+ * resulting instance of StringToTime
can be passed to any method
+ * or caller requiring a {@link Date} object. Unlike the static
+ * methods, attempting to create a StringToTime
instance with an
+ * invalid expression of time results in a {@link StringToTimeException}.
+ *
+ * All expressions are case-insensitive. + *
+ * + *now
(equal to new Date()
)today
(equal to StringToTime("00:00:00.000")
)midnight
(equal to
+ * StringToTime("00:00:00.000 +24 hours")
)morning
or this morning
(by default, equal to
+ * StringToTime("07:00:00.000")
)noon
(by default, equal to
+ * StringToTime("12:00:00.000")
afternoon
or this afternoon
(by default, equal
+ * to StringToTime("13:00:00.000")
evening
or this evening
(by default, equal to
+ * StringToTime("17:00:00.000")
tonight
(by default, equal to
+ * StringToTime("20:00:00.000")
tomorrow
(by default, equal to
+ * StringToTime("now +24 hours")
)tomorrow morning
(by default, equal to
+ * StringToTime("morning +24 hours")
)noon tomorrow
or tomorrow noon
(by default,
+ * equal to StringToTime("noon +24 hours")
)tomorrow afternoon
(by default, equal to
+ * StringToTime("afternoon +24 hours")
)yesterday
(by default, equal to
+ * StringToTime("now -24 hours")
)yesterday
and morning
,
+ * noon
, afternoon
, and evening
October 26, 1981
or Oct 26, 1981
October 26
or Oct 26
26 October 1981
26 Oct 1981
26 Oct 81
10/26/1981
or 10-26-1981
10/26/81
or 10-26-81
1981/10/26
or 1981-10-26
10/26
or 10-26
+ * Copied from github.com/collegeman/stringtotime + *
+ * + * @author Aaron Collegeman acollegeman@clutch-inc.com + * @since JRE 1.5.0 + * @see "https://us3.php.net/manual/en/function.strtotime.php" + */ +public final class StringToTime extends Date { + + private static final long serialVersionUID = 7889493424407815134L; + + // default SimpleDateFormat string is the standard MySQL date format + private static final String defaultSimpleDateFormat = "yyyy-MM-dd HH:mm:ss.SSS"; + private static final Locale DEFAULT_LOCALE = Locale.ENGLISH; + + // An expression of time (hour)(:(minute))?((:(second))(.(millisecond))?)?( + // *(am?|pm?))?(RFC 822 time zone|general time zone)? + private static final String timeExpr = "(\\d{1,2})(:(\\d{1,2}))?(:(\\d{1,2})(\\.(\\d{1,3}))?)?( *(am?|pm?))?( *\\-\\d{4})?"; + + /** + * Patterns and formats recognized by the algorithm; first match wins, so + * insert most specific patterns first. + */ + private static final PatternAndFormat[] known = { + + // TODO: ISO 8601 and derivatives + + // just the year + new PatternAndFormat(Pattern.compile("\\d{4}"), new Format(FormatType.YEAR)), + + // decrement, e.g., -1 day + new PatternAndFormat(Pattern.compile("-( *\\d+ +[^ ]+)+", Pattern.CASE_INSENSITIVE), new Format(FormatType.DECREMENT)), + + // increment, e.g., +1 day + new PatternAndFormat( + Pattern.compile("\\+( *\\d+ +[^ ]+)+", Pattern.CASE_INSENSITIVE),//patch x bliki, removed ? that caused problems parsing "31 July 1711 +11 days" + new Format(FormatType.INCREMENT) + ), + + + // e.g., October 26 and Oct 26 + new PatternAndFormat(Pattern.compile("([a-z]+) +(\\d{1,2})", Pattern.CASE_INSENSITIVE), new Format(FormatType.MONTH_AND_DATE)), + + // e.g., 26 October 1981, or 26 Oct 1981, or 26 Oct 81 + new PatternAndFormat(Pattern.compile("\\d{1,2} +[a-z]+ +(\\d{2}|\\d{4})", Pattern.CASE_INSENSITIVE), new Format("d MMM y")), + + // e.g., October 1981 + new PatternAndFormat(Pattern.compile("[a-z]+ +\\d{4}", Pattern.CASE_INSENSITIVE), new Format("MMM yyyy")), + + // now or today + new PatternAndFormat( + Pattern + .compile( + "(midnight|now|today|(this +)?(morning|afternoon|evening)|tonight|noon( +tomorrow)?|tomorrow|tomorrow +(morning|afternoon|evening|night|noon)?|yesterday|yesterday +(morning|afternoon|evening|night)?)", + Pattern.CASE_INSENSITIVE), new Format(FormatType.WORD)), + + // time, 24-hour and 12-hour + new PatternAndFormat(Pattern.compile(timeExpr, Pattern.CASE_INSENSITIVE), new Format(FormatType.TIME)), + + // e.g., 1997, March 14 + new PatternAndFormat(Pattern.compile("(\\d{2}|\\d{4}) *, *[a-z]+ +\\d{1,2}", Pattern.CASE_INSENSITIVE), + new Format("y, MMM d")), + + // e.g., October 26, 1981 or Oct 26, 1981 + new PatternAndFormat(Pattern.compile("[a-z]+ +\\d{1,2} *, *(\\d{2}|\\d{4})", Pattern.CASE_INSENSITIVE), + new Format("MMM d, y")), + + // e.g., October 26 1981 or Oct 26 1981 + new PatternAndFormat(Pattern.compile("[a-z]+ +\\d{1,2} +(\\d{2}|\\d{4})", Pattern.CASE_INSENSITIVE), + new Format("MMM d y")), + + // e.g., 10/26/1981 or 10/26/81 + new PatternAndFormat(Pattern.compile("\\d{1,2}/\\d{1,2}/\\d{2,4}"), new Format("M/d/y")), + + // e.g., 10-26-1981 or 10-26-81 + new PatternAndFormat(Pattern.compile("\\d{1,2}-\\d{1,2}-\\d{2,4}"), new Format("M-d-y")), + + // e.g., 10/26 or 10-26 + new PatternAndFormat(Pattern.compile("(\\d{1,2})([/\\-])(\\d{1,2})"), new Format(FormatType.MONTH_AND_DATE_WITH_SLASHES)), + + // e.g., 1981/10/26 + new PatternAndFormat(Pattern.compile("\\d{4}/\\d{1,2}/\\d{1,2}"), new Format("y/M/d")), + + // e.g., 19811026 + new PatternAndFormat(Pattern.compile("\\d{4}\\d{2}\\d{2}"), new Format("yyyyMMdd")), + + // e.g., 1981-10-26 + new PatternAndFormat(Pattern.compile("\\d{4}-\\d{1,2}-\\d{1,2}"), new Format("y-M-d")), + + // e.g., 1981-10 + new PatternAndFormat(Pattern.compile("\\d{4}-\\d{2}"), new Format("yyyy-MM")), + + // e.g., October or Oct + new PatternAndFormat( + Pattern + .compile( + "(Jan(uary)?|Feb(ruary)?|Mar(ch)?|Apr(il)?|May|Jun(e)?|Jul(y)?|Aug(ust)?|Sep(tember)?|Oct(ober)?|Nov(ember)?|Dec(ember)?)", + Pattern.CASE_INSENSITIVE), new Format(FormatType.MONTH)), + + // e.g., Tuesday or Tue + new PatternAndFormat(Pattern.compile("(Sun(day)?|Mon(day)?|Tue(sday)?|Wed(nesday)?|Thu(rsday)?|Fri(day)?|Sat(urday)?)", + Pattern.CASE_INSENSITIVE), new Format(FormatType.DAY_OF_WEEK)), + + // next, e.g., next Tuesday + new PatternAndFormat(Pattern.compile("next +(.*)", Pattern.CASE_INSENSITIVE), new Format(FormatType.NEXT)), + + // last, e.g., last Tuesday + new PatternAndFormat(Pattern.compile("last +(.*)", Pattern.CASE_INSENSITIVE), new Format(FormatType.LAST)), + + // compound statement + new PatternAndFormat( + Pattern.compile("(.*) *((([+\\-]).*)| "+timeExpr+")$", Pattern.CASE_INSENSITIVE), + new Format(FormatType.COMPOUND) + ) + + + }; + + /** The format to use in {@link #toString()} */ + private final String simpleDateFormat; + + public StringToTime(Object dateTimeString) { + this(dateTimeString, new Date(), defaultSimpleDateFormat); + } + + private StringToTime(Object dateTimeString, Date now) { + this(dateTimeString, now, defaultSimpleDateFormat); + } + + private StringToTime(Object dateTimeString, Date now, String simpleDateFormat) { + super(0); + assert dateTimeString != null; + assert now != null; + assert simpleDateFormat != null; + + /** Date/Time string parsed */ + this.simpleDateFormat = simpleDateFormat; + + /* + The {@link Date} interpreted from {@link #dateTimeString}, or + {@link Boolean}false
+ */ /**
+ * The {@link Date} interpreted from {@link #dateTimeString}, or
+ * {@link Boolean} false
+ */Object date = StringToTime.date(dateTimeString, now);
+ if (!Boolean.FALSE.equals(date))
+ setTime(((Date) date).getTime());
+ else {
+ throw new StringToTimeException(dateTimeString);
+ }
+ }
+
+ /**
+ * @return Calendar set to timestamp {@link Date#getTime()}
+ */
+ public Calendar getCal() {
+ Calendar cal = Calendar.getInstance();
+ cal.setTimeInMillis(super.getTime());
+ return cal;
+ }
+
+ /**
+ * @param simpleDateFormat
+ * @see SimpleDateFormat
+ * @return Date formatted according to simpleDateFormat
+ */
+ public String format(String simpleDateFormat) {
+ return new SimpleDateFormat(simpleDateFormat, DEFAULT_LOCALE).format(this);
+ }
+
+ /**
+ * @return If {@link #simpleDateFormat} provided in constructor, then attempts
+ * to format date
accordingly; otherwise, returns the
+ * String
value of {@link Date#getTime()}.
+ */
+ @Override
+ public String toString() {
+ if (simpleDateFormat != null)
+ return new SimpleDateFormat(simpleDateFormat, DEFAULT_LOCALE).format(this);
+ else
+ return new SimpleDateFormat("yyyy/dd/MM", DEFAULT_LOCALE).format(this); // String.valueOf(super.getTime());
+ }
+
+ /**
+ * A single parameter version of {@link #time(Object, Date)}, passing a new
+ * instance of {@link Date} as the second parameter.
+ *
+ * @param dateTimeString
+ * @return A {@link Long} timestamp representative of
+ * dateTimeString
, or {@link Boolean}
+ * false
.
+ * @see #time(Object, Date)
+ */
+ public static Object time(Object dateTimeString) {
+ return time(dateTimeString, new Date());
+ }
+
+ /**
+ * Parse dateTimeString
and produce a timestamp.
+ *
+ * @param dateTimeString
+ * @param now
+ * @return now
.now
.
+ * + * Typically, this library is included as part of a call to either + * {@link org.luaj.vm2.lib.jse.JsePlatform#standardGlobals()} or {@link org.luaj.vm2.lib.jme.JmePlatform#standardGlobals()} + *
{@code + * Globals globals = JsePlatform.standardGlobals(); + * System.out.println( globals.get("string").get("upper").call( LuaValue.valueOf("abcde") ) ); + * }+ *
+ * To instantiate and use it directly, + * link it into your globals table via {@link LuaValue#load(LuaValue)} using code such as: + *
{@code + * Globals globals = new Globals(); + * globals.load(new JseBaseLib()); + * globals.load(new PackageLib()); + * globals.load(new JseStringLib()); + * System.out.println( globals.get("string").get("upper").call( LuaValue.valueOf("abcde") ) ); + * }+ *
+ * This is a direct port of the corresponding library in C. + * @see LibFunction + * @see org.luaj.vm2.lib.jse.JsePlatform + * @see org.luaj.vm2.lib.jme.JmePlatform + * @see Lua 5.2 String Lib Reference + */ +public class StringLib extends TwoArgFunction { + + /** Construct a StringLib, which can be initialized by calling it with a + * modname string, and a global environment table as arguments using + * {@link #call(LuaValue, LuaValue)}. */ + public StringLib() { + } + + /** Perform one-time initialization on the library by creating a table + * containing the library functions, adding that table to the supplied environment, + * adding the table to package.loaded, and returning table as the return value. + * Creates a metatable that uses __INDEX to fall back on itself to support string + * method operations. + * If the shared strings metatable instance is null, will set the metatable as + * the global shared metatable for strings. + *
+ * All tables and metatables are read-write by default so if this will be used in
+ * a server environment, sandboxing should be used. In particular, the
+ * {@link LuaString#s_metatable} table should probably be made read-only.
+ * @param modname the module name supplied if this is loaded via 'require'.
+ * @param env the environment to load into, typically a Globals instance.
+ */
+ public LuaValue call(LuaValue modname, LuaValue env) {
+ LuaTable string = new LuaTable();
+ string.set("byte", new _byte());
+ string.set("char", new _char());
+ string.set("dump", new dump());
+ string.set("find", new find());
+ string.set("format", new format());
+ string.set("gmatch", new gmatch());
+ string.set("gsub", new gsub());
+ string.set("len", new len());
+ string.set("lower", new lower());
+ string.set("match", new match());
+ string.set("rep", new rep());
+ string.set("reverse", new reverse());
+ string.set("sub", new sub());
+ string.set("upper", new upper());
+
+ env.set("string", string);
+ if (!env.get("package").isnil()) env.get("package").get("loaded").set("string", string);
+ if (LuaString.s_metatable == null) {
+ LuaString.s_metatable = LuaValue.tableOf(new LuaValue[] { INDEX, string });
+ }
+ return string;
+ }
+
+ /**
+ * string.byte (s [, i [, j]])
+ *
+ * Returns the internal numerical codes of the
+ * characters s[i], s[i+1], ..., s[j]. The default value for i is 1; the
+ * default value for j is i.
+ *
+ * Note that numerical codes are not necessarily portable across platforms.
+ *
+ * @param args the calling args
+ */
+ static final class _byte extends VarArgFunction {
+ public Varargs invoke(Varargs args) {
+ LuaString s = args.checkstring(1);
+ int l = s.m_length;
+ int posi = posrelat( args.optint(2,1), l );
+ int pose = posrelat( args.optint(3,posi), l );
+ int n,i;
+ if (posi <= 0) posi = 1;
+ if (pose > l) pose = l;
+ if (posi > pose) return NONE; /* empty interval; return no values */
+ n = (int)(pose - posi + 1);
+ if (posi + n <= pose) /* overflow? */
+ error("string slice too long");
+ LuaValue[] v = new LuaValue[n];
+ for (i=0; i a%CkUJr23voz=`y$D(0Mp2Gt?|0A}bm?#b{!@rEiJfY^nV(Z~cJz(27}AdU
zBx+sH_j{P4J(pf7kRl{ge?7a(%0)!mW@ODYR(+iULXDceXrQ6}-L)g;<~8&l)mxs)
z2aMD7L;ETimR0#NXw(H*U?We_PI2X_MN2d~%RV`biaNv4Ij^r=@ BLEtw{-XsN!0y7*J~s
zs@K67u|EQmR~8~<52*XWxk(#J7C!A>9$;40B`>hwG;gv?I#fsXM*Q6*aTQx87T_l?
z#C$f7R31wW`&$^iB6x@kyq3H%Kcro5lv{18-K5|LasS65fL455MxX;Ma4KGV&40Ts
zIn@jFa^pj7_>3B$k4v+hwqx#r?PJfq1
zP{a`1Fap2SGRmuIv*4gCVl%Z3GemM&pr5owyT{lxG5HoLcFw$5Ag=_Hs;g@_^A)wC1V(9@&^dNp2QX%9
zRB$Fb>G6UrQ&bxzS4`ZeI&MJRH!ETBw7e6?jw~y44w%ZGORhYi>mR}IR!ntKvm_2d
zeUyQU?Iq|I*jY(RR2v9|iLxglB<)2hgn0J98$EDqZQ4*6Znws;gNN4j#Kgkh)!q%{
zprB@WRJEc&rz1%w=;wmPfv!&J=O}{w2SMNM7Jl=EFmEx^2XA6tqo;|eXqhl?8IOIA
z?m>$JCmn&R%+xLw_;y20gN!B5H8xMCnSNNV0C8!MxvrylO0K5PtwYk;C=-=ZAHxWG
zR>CW_piez|QRx%tIzY}(ZvoQ21(%(1w72C1itGcy?~=j;p>+~OMp}z+Q#6aHpmp#A
z&09l2e);J