ycl

Artifact [064d1bbac5]
Login

Artifact [064d1bbac5]

Artifact 064d1bbac501034927aa7bd82a82212f648b9913:


#! /usr/bin/env tclsh

package require {ycl chan clib}
package require sha256c 

::critcl::ccode {
	#include <string.h>
	#include <stdint.h>

	typedef struct state {
		char *channame;
		Tcl_Obj *list;
		/* current fragment size */ 
		int fsize;
		uint64_t cursor;
		unsigned int min_fragment;
		unsigned int max_fragment;
		/* rolling hash for finding fragment boundaries */
		uint32_t h;

		/* previous byte */
		Tcl_UniChar c1;

		/* order 1 context -> predicted byte */
		unsigned char o1[256];

		SHA256_CTX *mp;
		SHA256_CTX *wholemp;
	} state;

	int initialized = 0;
	Tcl_HashTable chanchunks;

	void finalize (ClientData clientData);

	int process(ClientData clientData ,Tcl_UniChar uchar , Tcl_DString *output) {
		state *s = clientData;
		int fragtune = 6;
		unsigned char byte;
		Tcl_Obj *cursorobj ,*tmp;
		uint8_t hash[SHA256_HASH_SIZE];
		Tcl_Obj *hashobj;
		if (uchar == s->o1[s->c1]) {
			s->h = (s->h + uchar + 1) * 31415926u;
		} else {
			s->h = (s->h + uchar + 1) * 271828182u;
		}
		Tcl_Channel *chan = Tcl_GetStdChannel(TCL_STDOUT);
		/*
		tmp = Tcl_NewWideIntObj(s->h);
		Tcl_WriteObj(chan ,tmp);
		Tcl_DecrRefCount(tmp);
		Tcl_Write(chan ,"\n", -1);
		tmp = Tcl_NewWideIntObj(s->h & 0x1f);
		Tcl_WriteObj(chan ,Tcl_NewWideIntObj(s->h & 0x1f));
		Tcl_DecrRefCount(tmp);
		Tcl_Write(chan ,"\n\n", -1);
		*/
		if ((s->h < (1u <<(22-fragtune)) && s->fsize >= s->min_fragment)
			|| s->fsize >= s->max_fragment) {
			cursorobj = Tcl_NewWideIntObj(s->cursor);

			/*
			Tcl_Write(chan ,"\n", -1);
			Tcl_WriteObj(chan ,cursorobj);
			Tcl_Write(chan ,"\n\n", -1);
			*/

			SHA256Final(s->mp ,hash);
			hashobj = Tcl_NewByteArrayObj(hash ,SHA256_HASH_SIZE);
			SHA256Init(s->mp);

			Tcl_ListObjAppendElement(NULL ,s->list ,cursorobj);
			Tcl_ListObjAppendElement(NULL ,s->list ,hashobj);
			s->h = 0;
			s->fsize = 0;
		}

		/*
		cursorobj = Tcl_NewWideIntObj(s->cursor);
		Tcl_Write(chan ,"\n", -1);
		Tcl_WriteObj(chan ,cursorobj);
		Tcl_DecrRefCount(cursorobj);
		*/

		byte = uchar;

		SHA256Update(s->mp ,&byte ,1);
		SHA256Update(s->wholemp ,&byte ,1);
		s->fsize++;
		s->o1[s->c1] = uchar;
		s->c1 = uchar;
		s->cursor++;
		return TCL_OK;
	}


	int closeProc (Tcl_Interp *interp ,ClientData clientData
		, Tcl_DString *output, int flags) {
		state *s = clientData;
		uint8_t hash[SHA256_HASH_SIZE];
		Tcl_Obj *cursorobj ,*hashobj;
		if (flags & TCL_CLOSE_READ)  {
		} else if (flags & TCL_CLOSE_WRITE)  {
		} else {
			if (s->fsize > 0) {
				cursorobj = Tcl_NewWideIntObj(s->cursor);
				Tcl_ListObjAppendElement(NULL ,s->list ,cursorobj);
				SHA256Final(s->mp ,hash);
				hashobj = Tcl_NewByteArrayObj(hash ,SHA256_HASH_SIZE);
				Tcl_ListObjAppendElement(NULL ,s->list ,hashobj);
				s->fsize = 0;
			}
			finalize(s);
		}
		return TCL_OK;
	}


	int eofProc (ClientData clientData) {
		state *s = clientData;
		Tcl_Obj *cursorobj ,*hashobj;
		uint8_t hash[SHA256_HASH_SIZE];
		if (s->fsize > 0) {
			cursorobj = Tcl_NewWideIntObj(s->cursor);
			Tcl_ListObjAppendElement(NULL ,s->list ,cursorobj);
			SHA256Final(s->mp ,hash);
			hashobj = Tcl_NewByteArrayObj(hash ,SHA256_HASH_SIZE);
			Tcl_ListObjAppendElement(NULL ,s->list ,hashobj);
			SHA256Init(s->mp);
			s->fsize = 0;
		}
		return TCL_OK;
	}

	void finalize (ClientData clientData) {
		state *s = clientData;
		char *name = s->channame;

		/*
			drop the refCount of this private Tcl_Obj to -1
		 */
		Tcl_DecrRefCount(s->list);

		Tcl_HashEntry *entry = Tcl_FindHashEntry(&chanchunks ,s->channame);
		Tcl_DeleteHashEntry(entry);
		ckfree(s->mp);
		ckfree(s->wholemp);
		ckfree(s->channame);
		ckfree(s);
		return;
	}

}


critcl::cproc cut {
	Tcl_Interp* interp char* channame} object {
	char * channame2;
	int isnew;
	if  (initialized == 0) {
		Tcl_InitHashTable(&chanchunks ,TCL_STRING_KEYS);
		initialized = 1;
	}
	Tcl_HashEntry *entry = Tcl_CreateHashEntry(&chanchunks ,channame ,&isnew);

	Tcl_Obj *list, *res;
	state *s = (state *)ckalloc(sizeof(state));
	memset(s ,0 ,sizeof(state));
	list = Tcl_NewListObj(0, NULL);
	Tcl_SetHashValue(entry ,s);
	channame2 = ckalloc(strlen(channame) + 1);
	memmove(channame2 ,channame ,(strlen(channame) + 1));
	s->channame = channame2;
	s->min_fragment = 8192;
	s->max_fragment = 16536;
	s->list = list;

	s->mp = (void *)ckalloc(sizeof(*s->mp));
	SHA256Init(s->mp);
	s->wholemp = (void *)ckalloc(sizeof(*s->mp));
	SHA256Init(s->wholemp);


	res = Tcl_NewObj();

	Tcl_IncrRefCount(res);
	if (pushTransform(interp ,(char *)channame, s, process ,eofProc ,closeProc
		,requireBinary()) != TCL_OK) {

		Tcl_DecrRefCount(res);
		finalize(s);
		return NULL;
	}
	return res;
}

critcl::cproc cuts {char* channame} object {
	Tcl_Obj *list ,*newlist;
	Tcl_HashEntry *entry;
	state *s;
	entry = Tcl_FindHashEntry(&chanchunks, channame);
	if (entry == NULL) {
		return NULL;
	}
	s = Tcl_GetHashValue(entry);
	list = s->list;
	s->list = Tcl_NewListObj(0 ,NULL);
	Tcl_IncrRefCount(list);
	return list; 
}

critcl::cproc signature_sha256 {char* channame} object {
	Tcl_Obj *hashobj;
	uint8_t hash[SHA256_HASH_SIZE];
	Tcl_HashEntry *entry = Tcl_FindHashEntry(&chanchunks, channame);
	if (entry == NULL) {
		return NULL;
	}
	state *s = Tcl_GetHashValue(entry);
	SHA256Final(s->wholemp ,hash);
	hashobj = Tcl_NewByteArrayObj(hash ,SHA256_HASH_SIZE);
	Tcl_IncrRefCount(hashobj);
	SHA256Init(s->wholemp);
	return  hashobj;
}

::critcl::api import sha256c 1
::critcl::api import ycl_chan_clib 0.1
::critcl::debug symbols
critcl::load