353 lines
6.6 KiB
C
353 lines
6.6 KiB
C
#include "nota.h"
|
|
#include "stdio.h"
|
|
#include "math.h"
|
|
#include "string.h"
|
|
#include "stdlib.h"
|
|
|
|
#define NOTA_CONT 0x80
|
|
#define NOTA_DATA 0x7f
|
|
#define NOTA_INT_DATA 0x07
|
|
#define NOTA_INT_SIGN(CHAR) (CHAR & (1<<3))
|
|
#define NOTA_SIG_SIGN(CHAR) (CHAR & (1<<3))
|
|
#define NOTA_EXP_SIGN(CHAR) (CHAR & (1<<4))
|
|
#define NOTA_TYPE 0x70
|
|
#define NOTA_HEAD_DATA 0x0f
|
|
#define CONTINUE(CHAR) (CHAR>>7)
|
|
|
|
#define NOTA_FALSE 0x00
|
|
#define NOTA_TRUE 0x01
|
|
#define NOTA_PRIVATE 0x08
|
|
#define NOTA_SYSTEM 0x09
|
|
|
|
#define UTF8_DATA 0x3f
|
|
|
|
int nota_type(char *nota) { return *nota & NOTA_TYPE; }
|
|
|
|
int nota_bits(long long n, int sb)
|
|
{
|
|
int bits;
|
|
if (n == 0)
|
|
bits = 0;
|
|
else
|
|
bits = ilogb(n)+1;
|
|
bits-=sb; /* start bit */
|
|
int chars = bits/7;
|
|
if (bits%7>0) chars++;
|
|
bits = sb + (chars*7);
|
|
return bits;
|
|
}
|
|
|
|
char *nota_continue_num(long long n, char *nota, int sb)
|
|
{
|
|
int bits = nota_bits(n, sb);
|
|
bits -= sb;
|
|
if (bits > 0)
|
|
nota[0] |= NOTA_CONT;
|
|
else
|
|
nota[0] &= ~NOTA_CONT;
|
|
|
|
int shex = ~0 << sb;
|
|
nota[0] &= shex; /* clear shex bits */
|
|
nota[0] |= ~shex & (n>>bits);
|
|
|
|
int i = 1;
|
|
while (bits > 0) {
|
|
bits -= 7;
|
|
int head = bits == 0 ? 0 : NOTA_CONT;
|
|
nota[i] = head | (NOTA_DATA & (n >> bits));
|
|
i++;
|
|
}
|
|
|
|
return ¬a[i];
|
|
}
|
|
|
|
|
|
void print_nota_hex(char *nota)
|
|
{
|
|
long long chars = 0;
|
|
if (!((*nota>>4 & 0x07) ^ NOTA_TEXT>>4)) {
|
|
nota_read_num(nota, &chars);
|
|
printf("print with %d points\n", chars);
|
|
}
|
|
|
|
if ((*nota>>5) == 2 || (*nota>>5) == 6)
|
|
chars = 1;
|
|
|
|
for (int i = 0; i < chars+1; i++) {
|
|
do {
|
|
printf("%02X ", (unsigned char)(*nota));
|
|
} while(CONTINUE(*(nota++)));
|
|
}
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
void nota_write_int(long long n, char *nota)
|
|
{
|
|
printf("number %lld\n", n);
|
|
char sign = 0;
|
|
|
|
if (n < 0) {
|
|
sign = 0x08;
|
|
n *= -1;
|
|
}
|
|
|
|
nota[0] = NOTA_INT | sign;
|
|
|
|
nota_continue_num(n, nota, 3);
|
|
print_nota_hex(nota);
|
|
}
|
|
|
|
char *nota_read_num(char *nota, long long *n)
|
|
{
|
|
*n = 0;
|
|
*n |= (*nota) & NOTA_HEAD_DATA;
|
|
|
|
while (CONTINUE(*(nota++)))
|
|
*n = (*n<<7) | (*nota) & NOTA_DATA;
|
|
|
|
return nota;
|
|
}
|
|
|
|
#define NOTA_DBL_PREC 6
|
|
#define xstr(s) str(s)
|
|
#define str(s) #s
|
|
|
|
void nota_write_float(double n, char *nota)
|
|
{
|
|
if (n == 0) {
|
|
nota_write_int(0, nota);
|
|
return;
|
|
}
|
|
|
|
int sign = n < 0 ? ~0 : 0;
|
|
if (sign) n *= -1;
|
|
char ns[2+NOTA_DBL_PREC+5];
|
|
snprintf(ns, 2+NOTA_DBL_PREC+5, "%." xstr (NOTA_DBL_PREC) "e", n);
|
|
|
|
int e = atoi(&ns[2+NOTA_DBL_PREC+1]);
|
|
ns[2+NOTA_DBL_PREC] = 0;
|
|
|
|
char *z = ns + 1 + NOTA_DBL_PREC;
|
|
while (*z == '0')
|
|
z--;
|
|
|
|
*(z+1) = 0;
|
|
|
|
int expadd = (ns+strlen(ns)) - strchr(ns,'.') - 1;
|
|
e-=expadd;
|
|
ns[1] = ns[0];
|
|
long long sig = atoll(ns+1);
|
|
|
|
if (e == 0) {
|
|
if (sign) sig*=-1;
|
|
nota_write_int(sig, nota);
|
|
return;
|
|
}
|
|
|
|
int expsign = e < 0 ? ~0 : 0;
|
|
if (expsign) e *= -1;
|
|
|
|
nota[0] = NOTA_FLOAT;
|
|
nota[0] |= 0x10 & expsign;
|
|
nota[0] |= 0x08 & sign;
|
|
|
|
char *c = nota_continue_num(e, nota, 3);
|
|
|
|
nota_continue_num(sig, c, 7);
|
|
|
|
printf("float number %g\n", n* (sign ? -1 : 1));
|
|
print_nota_hex(nota);
|
|
}
|
|
|
|
double nota_read_float(char *nota)
|
|
{
|
|
printf("reading ...\n");
|
|
print_nota_hex(nota);
|
|
long long sig;
|
|
long long e;
|
|
|
|
char *c = nota;
|
|
e = *c & NOTA_INT_DATA; /* first three bits */
|
|
while (CONTINUE(*(c++)))
|
|
e = (e<<7) | (*c) & NOTA_DATA;
|
|
|
|
c++;
|
|
sig = (*c) & NOTA_DATA;
|
|
while (CONTINUE(*(c++)))
|
|
sig = (sig<<7) | *c & NOTA_DATA;
|
|
|
|
if (NOTA_SIG_SIGN(*nota)) sig *= -1;
|
|
if (NOTA_EXP_SIGN(*nota)) e *= -1;
|
|
|
|
printf("got %lld x 10^%lld\n", sig, exp);
|
|
|
|
return (double)sig * pow(10.0, e);
|
|
}
|
|
|
|
long long nota_read_int(char *nota)
|
|
{
|
|
long long n = 0;
|
|
char *c = nota;
|
|
n |= (*c) & NOTA_INT_DATA; /* first three bits */
|
|
while (CONTINUE(*(c++)))
|
|
n = (n<<7) | (*c) & NOTA_DATA;
|
|
|
|
if (NOTA_INT_SIGN(*nota)) n *= -1;
|
|
return n;
|
|
}
|
|
|
|
/* n is the number of bits */
|
|
void nota_write_blob(unsigned long long n, char *nota)
|
|
{
|
|
printf("blob %lld\n", n);
|
|
nota[0] = NOTA_BLOB;
|
|
nota_continue_num(n, nota, 4);
|
|
print_nota_hex(nota);
|
|
}
|
|
|
|
void nota_write_array(unsigned long long n, char *nota)
|
|
{
|
|
printf("array %lld\n", n);
|
|
nota[0] = NOTA_ARR;
|
|
nota_continue_num(n, nota, 4);
|
|
print_nota_hex(nota);
|
|
}
|
|
|
|
/* kim is 7, 14, then 21 */
|
|
|
|
int utf8_bytes(char *s)
|
|
{
|
|
int bytes = __builtin_clz(~(*s));
|
|
if (!bytes) return 1;
|
|
return bytes-24;
|
|
}
|
|
|
|
int utf8_count(char *s)
|
|
{
|
|
int count = 0;
|
|
char *p = s;
|
|
|
|
while(*s) {
|
|
count++;
|
|
s += utf8_bytes(s);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
int decode_utf8(char **s) {
|
|
int k = **s ? __builtin_clz(~(**s << 24)) : 0; // Count # of leading 1 bits.
|
|
int mask = (1 << (8 - k)) - 1; // All 1's with k leading 0's.
|
|
int value = **s & mask;
|
|
for (++(*s), --k; k > 0 && **s; --k, ++(*s)) { // Note that k = #total bytes, or 0.
|
|
value <<= 6;
|
|
value += (**s & 0x3F);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
void encode_utf8(char **s, char *end, int code) {
|
|
if (code < 255) {
|
|
**s = code;
|
|
(*s)++;
|
|
return;
|
|
}
|
|
|
|
char val[4];
|
|
int lead_byte_max = 0x7F;
|
|
int val_index = 0;
|
|
while (code > lead_byte_max) {
|
|
val[val_index++] = (code & 0x3F) | 0x80;
|
|
code >>= 6;
|
|
lead_byte_max >>= (val_index == 1 ? 2 : 1);
|
|
}
|
|
val[val_index++] = (code & lead_byte_max) | (~lead_byte_max << 1);
|
|
while (val_index-- && *s < end) {
|
|
**s = val[val_index];
|
|
(*s)++;
|
|
}
|
|
}
|
|
|
|
void encode_kim(char **s, char *end, int code)
|
|
{
|
|
if (code < 255) {
|
|
**s = 0 | (NOTA_DATA & code);
|
|
(*s)++;
|
|
return;
|
|
}
|
|
|
|
int bits = 32 - __builtin_clz(code);
|
|
if (bits <= 7)
|
|
bits = 7;
|
|
else if (bits <= 14)
|
|
bits = 14;
|
|
else
|
|
bits = 21;
|
|
|
|
while (bits > 7) {
|
|
bits -= 7;
|
|
**s = NOTA_CONT | NOTA_DATA & (code >> bits);
|
|
(*s)++;
|
|
}
|
|
**s = NOTA_DATA & code;
|
|
(*s)++;
|
|
}
|
|
|
|
int decode_kim(char **s)
|
|
{
|
|
int rune = **s & NOTA_DATA;
|
|
while (CONTINUE(**s)) {
|
|
rune <<= 7;
|
|
(*s)++;
|
|
rune |= **s & NOTA_DATA;
|
|
}
|
|
(*s)++;
|
|
return rune;
|
|
}
|
|
|
|
void utf8_to_kim(char *utf, char *kim)
|
|
{
|
|
while (*utf)
|
|
encode_kim(&kim, NULL, decode_utf8(&utf));
|
|
}
|
|
|
|
void kim_to_utf8(char *kim, char *utf, int runes)
|
|
{
|
|
for (int i = 0; i < runes; i++)
|
|
encode_utf8(&utf, utf+4, decode_kim(&kim));
|
|
|
|
*utf = 0;
|
|
}
|
|
|
|
char *nota_read_text(char *nota)
|
|
{
|
|
long long chars;
|
|
nota = nota_read_num(nota, &chars);
|
|
printf("reading %d runes\n", chars);
|
|
char utf[chars*4];
|
|
kim_to_utf8(nota, utf, chars);
|
|
return strdup(utf);
|
|
}
|
|
|
|
void nota_write_bool(int b, char *nota)
|
|
{
|
|
*nota = NOTA_SYM | (b ? NOTA_TRUE : NOTA_FALSE);
|
|
}
|
|
|
|
int nota_read_bool(char *nota)
|
|
{
|
|
return *nota & 0x0f;
|
|
}
|
|
|
|
void nota_write_text(char *s, char *nota)
|
|
{
|
|
char *start = nota;
|
|
nota[0] = NOTA_TEXT;
|
|
long n = utf8_count(s);
|
|
printf("text %s with %d points\n", s, n);
|
|
nota = nota_continue_num(n,nota,4);
|
|
utf8_to_kim(s, nota);
|
|
print_nota_hex(start);
|
|
}
|