mirror of
https://github.com/janeczku/calibre-web
synced 2024-08-30 13:02:41 +00:00
![OzzieIsaacs](/assets/img/avatar_default.png)
Bugfix for feeds - removed categories related and up - load new books now working - category random now working login page is free of non accessible elements boolean custom column is vivible in UI books with only with certain languages can be shown book shelfs can be deleted from UI Anonymous user view is more resticted Added browse of series in sidebar Dependencys in vendor folder are updated to newer versions (licencs files are now present) Bugfix editing Authors names Made upload on windows working
274 lines
7.6 KiB
Python
274 lines
7.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
# This module is based on the excellent work by Adam Bartoš who
|
|
# provided a lot of what went into the implementation here in
|
|
# the discussion to issue1602 in the Python bug tracker.
|
|
#
|
|
# There are some general differences in regards to how this works
|
|
# compared to the original patches as we do not need to patch
|
|
# the entire interpreter but just work in our little world of
|
|
# echo and prmopt.
|
|
|
|
import io
|
|
import os
|
|
import sys
|
|
import zlib
|
|
import time
|
|
import ctypes
|
|
import msvcrt
|
|
from click._compat import _NonClosingTextIOWrapper, text_type, PY2
|
|
from ctypes import byref, POINTER, c_int, c_char, c_char_p, \
|
|
c_void_p, py_object, c_ssize_t, c_ulong, windll, WINFUNCTYPE
|
|
try:
|
|
from ctypes import pythonapi
|
|
PyObject_GetBuffer = pythonapi.PyObject_GetBuffer
|
|
PyBuffer_Release = pythonapi.PyBuffer_Release
|
|
except ImportError:
|
|
pythonapi = None
|
|
from ctypes.wintypes import LPWSTR, LPCWSTR
|
|
|
|
|
|
c_ssize_p = POINTER(c_ssize_t)
|
|
|
|
kernel32 = windll.kernel32
|
|
GetStdHandle = kernel32.GetStdHandle
|
|
ReadConsoleW = kernel32.ReadConsoleW
|
|
WriteConsoleW = kernel32.WriteConsoleW
|
|
GetLastError = kernel32.GetLastError
|
|
GetCommandLineW = WINFUNCTYPE(LPWSTR)(
|
|
('GetCommandLineW', windll.kernel32))
|
|
CommandLineToArgvW = WINFUNCTYPE(
|
|
POINTER(LPWSTR), LPCWSTR, POINTER(c_int))(
|
|
('CommandLineToArgvW', windll.shell32))
|
|
|
|
|
|
STDIN_HANDLE = GetStdHandle(-10)
|
|
STDOUT_HANDLE = GetStdHandle(-11)
|
|
STDERR_HANDLE = GetStdHandle(-12)
|
|
|
|
|
|
PyBUF_SIMPLE = 0
|
|
PyBUF_WRITABLE = 1
|
|
|
|
ERROR_SUCCESS = 0
|
|
ERROR_NOT_ENOUGH_MEMORY = 8
|
|
ERROR_OPERATION_ABORTED = 995
|
|
|
|
STDIN_FILENO = 0
|
|
STDOUT_FILENO = 1
|
|
STDERR_FILENO = 2
|
|
|
|
EOF = b'\x1a'
|
|
MAX_BYTES_WRITTEN = 32767
|
|
|
|
|
|
class Py_buffer(ctypes.Structure):
|
|
_fields_ = [
|
|
('buf', c_void_p),
|
|
('obj', py_object),
|
|
('len', c_ssize_t),
|
|
('itemsize', c_ssize_t),
|
|
('readonly', c_int),
|
|
('ndim', c_int),
|
|
('format', c_char_p),
|
|
('shape', c_ssize_p),
|
|
('strides', c_ssize_p),
|
|
('suboffsets', c_ssize_p),
|
|
('internal', c_void_p)
|
|
]
|
|
|
|
if PY2:
|
|
_fields_.insert(-1, ('smalltable', c_ssize_t * 2))
|
|
|
|
|
|
# On PyPy we cannot get buffers so our ability to operate here is
|
|
# serverly limited.
|
|
if pythonapi is None:
|
|
get_buffer = None
|
|
else:
|
|
def get_buffer(obj, writable=False):
|
|
buf = Py_buffer()
|
|
flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE
|
|
PyObject_GetBuffer(py_object(obj), byref(buf), flags)
|
|
try:
|
|
buffer_type = c_char * buf.len
|
|
return buffer_type.from_address(buf.buf)
|
|
finally:
|
|
PyBuffer_Release(byref(buf))
|
|
|
|
|
|
class _WindowsConsoleRawIOBase(io.RawIOBase):
|
|
|
|
def __init__(self, handle):
|
|
self.handle = handle
|
|
|
|
def isatty(self):
|
|
io.RawIOBase.isatty(self)
|
|
return True
|
|
|
|
|
|
class _WindowsConsoleReader(_WindowsConsoleRawIOBase):
|
|
|
|
def readable(self):
|
|
return True
|
|
|
|
def readinto(self, b):
|
|
bytes_to_be_read = len(b)
|
|
if not bytes_to_be_read:
|
|
return 0
|
|
elif bytes_to_be_read % 2:
|
|
raise ValueError('cannot read odd number of bytes from '
|
|
'UTF-16-LE encoded console')
|
|
|
|
buffer = get_buffer(b, writable=True)
|
|
code_units_to_be_read = bytes_to_be_read // 2
|
|
code_units_read = c_ulong()
|
|
|
|
rv = ReadConsoleW(self.handle, buffer, code_units_to_be_read,
|
|
byref(code_units_read), None)
|
|
if GetLastError() == ERROR_OPERATION_ABORTED:
|
|
# wait for KeyboardInterrupt
|
|
time.sleep(0.1)
|
|
if not rv:
|
|
raise OSError('Windows error: %s' % GetLastError())
|
|
|
|
if buffer[0] == EOF:
|
|
return 0
|
|
return 2 * code_units_read.value
|
|
|
|
|
|
class _WindowsConsoleWriter(_WindowsConsoleRawIOBase):
|
|
|
|
def writable(self):
|
|
return True
|
|
|
|
@staticmethod
|
|
def _get_error_message(errno):
|
|
if errno == ERROR_SUCCESS:
|
|
return 'ERROR_SUCCESS'
|
|
elif errno == ERROR_NOT_ENOUGH_MEMORY:
|
|
return 'ERROR_NOT_ENOUGH_MEMORY'
|
|
return 'Windows error %s' % errno
|
|
|
|
def write(self, b):
|
|
bytes_to_be_written = len(b)
|
|
buf = get_buffer(b)
|
|
code_units_to_be_written = min(bytes_to_be_written,
|
|
MAX_BYTES_WRITTEN) // 2
|
|
code_units_written = c_ulong()
|
|
|
|
WriteConsoleW(self.handle, buf, code_units_to_be_written,
|
|
byref(code_units_written), None)
|
|
bytes_written = 2 * code_units_written.value
|
|
|
|
if bytes_written == 0 and bytes_to_be_written > 0:
|
|
raise OSError(self._get_error_message(GetLastError()))
|
|
return bytes_written
|
|
|
|
|
|
class ConsoleStream(object):
|
|
|
|
def __init__(self, text_stream, byte_stream):
|
|
self._text_stream = text_stream
|
|
self.buffer = byte_stream
|
|
|
|
@property
|
|
def name(self):
|
|
return self.buffer.name
|
|
|
|
def write(self, x):
|
|
if isinstance(x, text_type):
|
|
return self._text_stream.write(x)
|
|
try:
|
|
self.flush()
|
|
except Exception:
|
|
pass
|
|
return self.buffer.write(x)
|
|
|
|
def writelines(self, lines):
|
|
for line in lines:
|
|
self.write(line)
|
|
|
|
def __getattr__(self, name):
|
|
return getattr(self._text_stream, name)
|
|
|
|
def isatty(self):
|
|
return self.buffer.isatty()
|
|
|
|
def __repr__(self):
|
|
return '<ConsoleStream name=%r encoding=%r>' % (
|
|
self.name,
|
|
self.encoding,
|
|
)
|
|
|
|
|
|
def _get_text_stdin(buffer_stream):
|
|
text_stream = _NonClosingTextIOWrapper(
|
|
io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)),
|
|
'utf-16-le', 'strict', line_buffering=True)
|
|
return ConsoleStream(text_stream, buffer_stream)
|
|
|
|
|
|
def _get_text_stdout(buffer_stream):
|
|
text_stream = _NonClosingTextIOWrapper(
|
|
_WindowsConsoleWriter(STDOUT_HANDLE),
|
|
'utf-16-le', 'strict', line_buffering=True)
|
|
return ConsoleStream(text_stream, buffer_stream)
|
|
|
|
|
|
def _get_text_stderr(buffer_stream):
|
|
text_stream = _NonClosingTextIOWrapper(
|
|
_WindowsConsoleWriter(STDERR_HANDLE),
|
|
'utf-16-le', 'strict', line_buffering=True)
|
|
return ConsoleStream(text_stream, buffer_stream)
|
|
|
|
|
|
if PY2:
|
|
def _hash_py_argv():
|
|
return zlib.crc32('\x00'.join(sys.argv[1:]))
|
|
|
|
_initial_argv_hash = _hash_py_argv()
|
|
|
|
def _get_windows_argv():
|
|
argc = c_int(0)
|
|
argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))
|
|
argv = [argv_unicode[i] for i in range(0, argc.value)]
|
|
|
|
if not hasattr(sys, 'frozen'):
|
|
argv = argv[1:]
|
|
while len(argv) > 0:
|
|
arg = argv[0]
|
|
if not arg.startswith('-') or arg == '-':
|
|
break
|
|
argv = argv[1:]
|
|
if arg.startswith(('-c', '-m')):
|
|
break
|
|
|
|
return argv[1:]
|
|
|
|
|
|
_stream_factories = {
|
|
0: _get_text_stdin,
|
|
1: _get_text_stdout,
|
|
2: _get_text_stderr,
|
|
}
|
|
|
|
|
|
def _get_windows_console_stream(f, encoding, errors):
|
|
if get_buffer is not None and \
|
|
encoding in ('utf-16-le', None) \
|
|
and errors in ('strict', None) and \
|
|
hasattr(f, 'isatty') and f.isatty():
|
|
func = _stream_factories.get(f.fileno())
|
|
if func is not None:
|
|
if not PY2:
|
|
f = getattr(f, 'buffer')
|
|
if f is None:
|
|
return None
|
|
else:
|
|
# If we are on Python 2 we need to set the stream that we
|
|
# deal with to binary mode as otherwise the exercise if a
|
|
# bit moot. The same problems apply as for
|
|
# get_binary_stdin and friends from _compat.
|
|
msvcrt.setmode(f.fileno(), os.O_BINARY)
|
|
return func(f)
|