FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

GitHub Viewer

import codecs import re import types import sys from .constants import EOF, spaceCharacters, asciiLetters, asciiUppercase from .constants import encodings, ReparseException #Non-unicode versions of constants for use in the pre-parser spaceCharactersBytes = [str(item) for item in spaceCharacters] asciiLettersBytes = [str(item) for item in asciiLetters] asciiUppercaseBytes = [str(item) for item in asciiUppercase] invalid_unicode_re = re.compile("[\u0001-\u0008\u000B\u000E-\u001F\u007F-\u009F\uD800-\uDFFF\uFDD0-\uFDDF\uFFFE\uFFFF\U0001FFFE\U0001FFFF\U0002FFFE\U0002FFFF\U0003FFFE\U0003FFFF\U0004FFFE\U0004FFFF\U0005FFFE\U0005FFFF\U0006FFFE\U0006FFFF\U0007FFFE\U0007FFFF\U0008FFFE\U0008FFFF\U0009FFFE\U0009FFFF\U000AFFFE\U000AFFFF\U000BFFFE\U000BFFFF\U000CFFFE\U000CFFFF\U000DFFFE\U000DFFFF\U000EFFFE\U000EFFFF\U000FFFFE\U000FFFFF\U0010FFFE\U0010FFFF]") ascii_punctuation_re = re.compile(r"[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]") # Cache for charsUntil() charsUntilRegEx = {} class BufferedStream: """Buffering for streams that do not have buffering of their own The buffer is implemented as a list of chunks on the assumption that joining many strings will be slow since it is O(n**2) """ def __init__(self, stream): self.stream = stream self.buffer = [] self.position = [-1,0] #chunk number, offset def tell(self): pos = 0 for chunk in self.buffer[:self.position[0]]: pos += len(chunk) pos += self.position[1] return pos def seek(self, pos): assert pos < self._bufferedBytes() offset = pos i = 0 while len(self.buffer[i]) < offset: offset -= pos i += 1 self.position = [i, offset] def read(self, bytes): if not self.buffer: return self._readStream(bytes) elif (self.position[0] == len(self.buffer) and self.position[1] == len(self.buffer[-1])): return self._readStream(bytes) else: return self._readFromBuffer(bytes) def _bufferedBytes(self): return sum([len(item) for item in self.buffer]) def _readStream(self, bytes): data = self.stream.read(bytes) self.buffer.append(data) self.position[0] += 1 self.position[1] = len(data) return data def _readFromBuffer(self, bytes): remainingBytes = bytes rv = [] bufferIndex = self.position[0] bufferOffset = self.position[1] while bufferIndex < len(self.buffer) and remainingBytes != 0: assert remainingBytes > 0 bufferedData = self.buffer[bufferIndex] if remainingBytes = self.chunkSize: if not self.readChunk(): return EOF char = self.chunk[self.chunkOffset] self.chunkOffset += 1 # Update the position attributes if char == "\n": self.lastLineLength = self.positionCol self.positionCol = 0 self.positionLine += 1 elif char is not EOF: self.positionCol += 1 return char def readChunk(self, chunkSize=_defaultChunkSize): self.chunk = "" self.chunkSize = 0 self.chunkOffset = 0 data = self.dataStream.read(chunkSize) if not data: return False #Replace null characters for i in range(data.count("\u0000")): self.errors.append("null-character") for i in range(len(invalid_unicode_re.findall(data))): self.errors.append("invalid-codepoint") data = data.replace("\u0000", "\ufffd") #Check for CR LF broken across chunks if (self._lastChunkEndsWithCR and data[0] == "\n"): data = data[1:] # Stop if the chunk is now empty if not data: return False self._lastChunkEndsWithCR = data[-1] == "\r" data = data.replace("\r\n", "\n") data = data.replace("\r", "\n") self.chunk = data self.chunkSize = len(data) return True def charsUntil(self, characters, opposite = False): """ Returns a string of characters from the stream up to but not including any character in 'characters' or EOF. 'characters' must be a container that supports the 'in' method and iteration over its characters. """ # Use a cache of regexps to find the required characters try: chars = charsUntilRegEx[(characters, opposite)] except KeyError: for c in characters: assert(ord(c) < 128) regex = "".join(["\\x%02x" % ord(c) for c in characters]) if not opposite: regex = "^%s" % regex chars = charsUntilRegEx[(characters, opposite)] = re.compile("[%s]+" % regex) rv = [] while True: # Find the longest matching prefix m = chars.match(self.chunk, self.chunkOffset) if m is None: # If nothing matched, and it wasn't because we ran out of chunk, # then stop if self.chunkOffset != self.chunkSize: break else: end = m.end() # If not the whole chunk matched, return everything # up to the part that didn't match if end != self.chunkSize: rv.append(self.chunk[self.chunkOffset:end]) self.chunkOffset = end break # If the whole remainder of the chunk matched, # use it all and read the next chunk rv.append(self.chunk[self.chunkOffset:]) if not self.readChunk(): # Reached EOF break r = "".join(rv) self.updatePosition(r) return r def unget(self, char): # Only one character is allowed to be ungotten at once - it must # be consumed again before any further call to unget if char is not None: if self.chunkOffset == 0: # unget is called quite rarely, so it's a good idea to do # more work here if it saves a bit of work in the frequently # called char and charsUntil. # So, just prepend the ungotten character onto the current # chunk: self.chunk = char + self.chunk self.chunkSize += 1 else: self.chunkOffset -= 1 assert self.chunk[self.chunkOffset] == char # Update the position attributes if char == "\n": assert self.positionLine >= 1 assert self.lastLineLength is not None self.positionLine -= 1 self.positionCol = self.lastLineLength self.lastLineLength = None else: self.positionCol -= 1 class EncodingBytes(bytes): """Bytes-like object with an assosiated position and various extra methods If the position is ever greater than the string length then an exception is raised""" def __new__(self, value): return bytes.__new__(self, value) def __init__(self, value): self._position = -1 def __iter__(self): return self def __next__(self): self._position += 1 rv = self[self.position] return rv def setPosition(self, position): if self._position >= len(self): raise StopIteration self._position = position def getPosition(self): if self._position >= len(self): raise StopIteration if self._position >= 0: return self._position else: return None position = property(getPosition, setPosition) def getCurrentByte(self): return self[self.position] currentByte = property(getCurrentByte) def skip(self, chars=spaceCharactersBytes): """Skip past a list of characters""" while self.currentByte in chars: self.position += 1 def matchBytes(self, bytes, lower=False): """Look for a sequence of bytes at the start of a string. If the bytes are found return True and advance the position to the byte after the match. Otherwise return False and leave the position alone""" data = self[self.position:self.position+len(bytes)] if lower: data = data.lower() rv = data.startswith(bytes) if rv == True: self.position += len(bytes) return rv def jumpTo(self, bytes): """Look for the next sequence of bytes matching a given sequence. If a match is found advance the position to the last byte of the match""" newPosition = self[self.position:].find(bytes) if newPosition > -1: self._position += (newPosition + len(bytes)-1) return True else: raise StopIteration def findNext(self, byteList): """Move the pointer so it points to the next byte in a set of possible bytes""" while (self.currentByte not in byteList): self.position += 1 class EncodingParser(object): """Mini parser for detecting character encoding from meta elements""" def __init__(self, data): """data - the data to work on for encoding detection""" self.data = EncodingBytes(data) self.encoding = None def getEncoding(self): methodDispatch = ( (b"") def handleMeta(self): if self.data.currentByte not in spaceCharactersBytes: #if we have

Back | FazBrowse Home | New Git URL