Download | Plain Text | No Line Numbers
- #include <assert.h>
- #include "EXTERN.h"
- #include "perl.h"
- #include "XSUB.h"
- #include "ppport.h"
- #include "../cipher.h"
-
- #define BLOCKSIZE 8192
-
- #define SET_LEN(sv, len) \
- do { SvPVX(sv)[len] = '\0'; SvCUR_set(sv, len); } while (0)
-
- /* Internal defines */
- #ifdef PERL_FILTER_EXISTS
- # define CORE_FILTER_COUNT \
- ((PL_parser && PL_parser->rsfp_filters) ? av_len(PL_parser->rsfp_filters) : 0)
- #else
- # define CORE_FILTER_COUNT \
- ((PL_rsfp_filters) ? av_len(PL_rsfp_filters) : 0)
- #endif
-
- #define FILTER_COUNT(s) IoPAGE(s)
- #define FILTER_LINE_NO(s) IoLINES(s)
- #define FIRST_TIME(s) IoLINES_LEFT(s)
-
- #define CIPHER_GV(s) IoFMT_GV(s)
- #define CIPHER_SV(s) ((SV *) CIPHER_GV(s))
- #define CIPHER_BUFFER(s) ((ctx_t *)SvPVX(CIPHER_SV(s)))
- #define CLEAR_CIPHER_SV(s) SvCUR_set(CIPHER_SV(s), 0)
-
- #define ENCRYPT_GV(s) IoTOP_GV(s)
- #define ENCRYPT_SV(s) ((SV *) ENCRYPT_GV(s))
- #define ENCRYPT_BUFFER(s) SvPVX(ENCRYPT_SV(s))
- #define CLEAR_ENCRYPT_SV(s) SvCUR_set(ENCRYPT_SV(s), 0)
-
- #define DECRYPT_SV(s) s
- #define DECRYPT_BUFFER(s) SvPVX(DECRYPT_SV(s))
- #define CLEAR_DECRYPT_SV(s) SvCUR_set(DECRYPT_SV(s), 0)
- #define DECRYPT_BUFFER_LEN(s) SvCUR(DECRYPT_SV(s))
- #define DECRYPT_OFFSET(s) IoPAGE_LEN(DECRYPT_SV(s))
- #define SET_DECRYPT_BUFFER_LEN(s, n) SvCUR_set(DECRYPT_SV(s), n)
-
- static unsigned
- decrypt(SV *in_cipher, SV *in_sv, SV *out_sv)
- {
- /* here is where the actual decryption takes place */
- ctx_t *cipher = (ctx_t *)SvPVX(in_cipher);
- char *in_buffer = (char *)SvPVX(in_sv);
- char *out_buffer;
- size_t in_len = SvCUR(in_sv);
- size_t out_len;
-
- /* make certain that the output buffer is big enough
- * as the output from the decryption can never be larger than
- * the input buffer, make it that size
- */
- SvGROW(out_sv, in_len);
- out_buffer = (char *)SvPVX(out_sv);
-
- /* decrypt */
- out_len = CipherUpdate(cipher, in_buffer, in_len);
-
- /* input has been consumed, so set length to 0 */
- SET_LEN(in_sv, 0);
-
- /* set decrypt buffer length */
- SET_LEN(out_sv, out_len);
-
- /* return the size of the decrypt buffer */
- return out_len;
- }
-
- static int
- readblock(int idx, SV *sv, unsigned size)
- {
- /* read *exactly* size bytes from the next filter */
- int i = size;
- while (1)
- {
- int n = FILTER_READ(idx, sv, i);
- /* eof/error when nothing read so far */
- if (n <= 0 && i == size)
- return n;
- /* eof/error when something already read */
- if (n <= 0)
- return size - i;
- if (n == i)
- return size;
- i -= n;
- }
- }
-
- static void
- pre_decrypt(int idx)
- {}
-
- static void
- post_decrypt(int idx)
- {}
-
- static I32
- filter_decrypt(pTHX_ int idx, SV *buf_sv, int maxlen)
- {
- char *out_ptr;
- char *p;
- char *nl = "\n";
- int n;
- SV *my_sv = FILTER_DATA(idx);
-
- /* check if this is the first time through */
- if (FIRST_TIME(my_sv))
- {
- /* mild paranoia mode - make sure that no extra filters have
- * been applied on the same line as the use Filter::decrypt
- */
- if (CORE_FILTER_COUNT > FILTER_COUNT(my_sv))
- croak("too many filters");
-
- /* as this is the first time through, so deal with any
- * initialisation required
- */
- pre_decrypt(idx);
-
- FIRST_TIME(my_sv) = FALSE;
- SET_LEN(DECRYPT_SV(my_sv), 0);
- SET_LEN(ENCRYPT_SV(my_sv), 0);
- DECRYPT_OFFSET(my_sv) = 0;
- }
-
- #ifdef DEBUG
- warn("**** In filter_decrypt - maxlen = %d, len buf = %d idx = %d\n",
- maxlen, SvCUR(buf_sv), idx);
- #endif
-
- while (1)
- {
- /* anything left from last time */
- if ((n = SvCUR(DECRYPT_SV(my_sv))))
- {
- out_ptr = SvPVX(DECRYPT_SV(my_sv)) + DECRYPT_OFFSET(my_sv);
- if (maxlen)
- {
- /* want a block */
- #ifdef DEBUG
- warn("BLOCK(%d): size = %d, maxlen = %d\n", idx, n, maxlen);
- #endif
-
- sv_catpvn(buf_sv, out_ptr, (maxlen > n) ? n : maxlen);
- if (n <= maxlen)
- {
- DECRYPT_OFFSET(my_sv) = 0;
- SET_LEN(DECRYPT_SV(my_sv), 0);
- }
- else
- {
- DECRYPT_OFFSET(my_sv) += maxlen;
- SvCUR_set(DECRYPT_SV(my_sv), n - maxlen);
- }
- return SvCUR(buf_sv);
- }
- else
- {
- /* want lines */
- if ((p = ninstr(out_ptr, out_ptr + n, nl, nl + 1)))
- {
- sv_catpvn(buf_sv, out_ptr, p - out_ptr + 1);
- n = n - (p - out_ptr + 1);
- DECRYPT_OFFSET(my_sv) += (p - out_ptr + 1);
- SvCUR_set(DECRYPT_SV(my_sv), n);
- #ifdef DEBUG
- warn("recycle(%d): leaving %d, returning %d [%.999s]\n",
- idx, n, SvCUR(buf_sv), SvPVX(buf_sv));
- #endif
- return SvCUR(buf_sv);
- }
- else
- {
- /* no EOL, so append the complete buffer */
- sv_catpvn(buf_sv, out_ptr, n);
- }
- }
- }
-
- SET_LEN(DECRYPT_SV(my_sv), 0);
- DECRYPT_OFFSET(my_sv) = 0;
-
- /* read at most BLOCKSIZE - 1 bytes from the file into the encrypt buffer:
- * - 1 char ("#"-char) will be prepended during first call of CipherUpdate()
- * - 1 char is needed for the string termination BUT perl already
- * allocates +1 byte with newSV()
- */
- if ((n = readblock(idx + 1, ENCRYPT_SV(my_sv), BLOCKSIZE - 1)) <= 0)
- {
- /* either EOF or an error */
- #ifdef DEBUG
- warn("filter_read(%d): returned %d, returning %d\n", idx, n,
- (SvCUR(buf_sv) > 0) ? SvCUR(buf_sv) : n);
- #endif
-
- /* if the decrypt code needs to tidy up on EOF/error,
- * now is the time - here is a hook
- */
- post_decrypt(idx);
- filter_del(filter_decrypt);
-
- /* if error, return the code */
- if (n < 0)
- return n;
-
- /* return what we have so far else signal eof */
- return (SvCUR(buf_sv) > 0) ? SvCUR(buf_sv) : n;
- }
- #ifdef DEBUG
- else
- warn("filter_read(%d): read %d bytes\n", idx, n);
- #endif
-
- #ifdef DEBUG
- warn("filter_decrypt(%d): sub-filter returned %d: '%.999s'\n",
- idx, n, SvPV(my_sv, PL_na));
- #endif
-
- /* now decrypt a block */
- n = decrypt(CIPHER_SV(my_sv), ENCRYPT_SV(my_sv), DECRYPT_SV(my_sv));
-
- #ifdef DEBUG
- warn("decrypt(%d): returned %d [%.999s]\n", idx, n, SvPVX(DECRYPT_SV(my_sv)));
- #endif
- }
- }
-
-
- MODULE = Confixx::Filter PACKAGE = Confixx::Filter
-
- PROTOTYPES: DISABLE
-
- BOOT:
- {
- #ifndef BYPASS
- /* don't run if this module is dynamically linked */
- if (!isALPHA(SvPV(GvSV(CvFILEGV(cv)), PL_na)[0]))
- croak("module is dynamically linked. Recompile as a static module");
- #ifdef DEBUGGING
- /* don't run if compiled with DEBUGGING */
- croak("recompile without -DDEBUGGING");
- #endif
-
- /* double check that DEBUGGING hasn't been enabled */
- if (PL_debug)
- croak("debugging flags detected");
- #endif
- }
-
- void
- import(module)
- SV *module
- PPCODE:
- {
- int ret;
- SV *sv;
-
- /* main/decrypted SV */
- DECRYPT_SV(sv) = newSV(BLOCKSIZE);
- (void) SvPOK_only(DECRYPT_SV(sv));
- SET_LEN(DECRYPT_SV(sv), 0);
-
- /* add filter */
- filter_add(filter_decrypt, DECRYPT_SV(sv));
-
- /* cipher SV */
- CIPHER_GV(sv) = (GV *)newSV(sizeof(ctx_t));
- (void) SvPOK_only(CIPHER_GV(sv));
- ret = CipherInit(CIPHER_BUFFER(sv));
- if (ret != 256)
- croak("unexpected return value of CipherInit(): %d\n", ret);
-
- /* copy pointer to output buffer inside ciphers first bytes */
- CIPHER_BUFFER(sv)->out = DECRYPT_BUFFER(sv);
-
- /* encrypted SV */
- ENCRYPT_GV(sv) = (GV *)newSV(BLOCKSIZE);
- (void) SvPOK_only(ENCRYPT_SV(sv));
- SET_LEN(ENCRYPT_SV(sv), 0);
-
- /* enable first time flag */
- FIRST_TIME(sv) = TRUE;
- /* remember how many filters are enabled */
- FILTER_COUNT(sv) = CORE_FILTER_COUNT;
- /* and the line number */
- FILTER_LINE_NO(sv) = PL_curcop->cop_line;
- }
-
- void
- unimport(...)
- PPCODE:
- //filter_del(filter_decrypt);
-