Merge branch 'master' into master

This commit is contained in:
marshmellow42 2018-09-18 22:12:11 -04:00 committed by GitHub
commit 161c40fb52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 6730 additions and 449 deletions

View file

@ -20,6 +20,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Rewritten Legic Prime reader (`hf legic reader`, `write` and `fill`) - it is using xcorrelation now (AntiCat) - Rewritten Legic Prime reader (`hf legic reader`, `write` and `fill`) - it is using xcorrelation now (AntiCat)
- `hf 14a` commands works via argtable3 commandline parsing library (Merlok) - `hf 14a` commands works via argtable3 commandline parsing library (Merlok)
- HID LF operations on firmware updated for complete native support of long (>37 bit) HID tags (grauerfuchs) - HID LF operations on firmware updated for complete native support of long (>37 bit) HID tags (grauerfuchs)
- Changed Legic Prime tag simulator (`hf legic sim`) to run from 212 kHz SSP clock for better reliability (AntiCat)
### Fixed ### Fixed
- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok) - Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok)

View file

@ -112,10 +112,10 @@ void SetupSpi(int mode)
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Set up the synchronous serial port, with the one set of options that we // Set up the synchronous serial port with the set of options that fits
// always use when we are talking to the FPGA. Both RX and TX are enabled. // the FPGA mode. Both RX and TX are always enabled.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void FpgaSetupSsc(void) void FpgaSetupSsc(uint8_t FPGA_mode)
{ {
// First configure the GPIOs, and get ourselves a clock. // First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR = AT91C_BASE_PIOA->PIO_ASR =
@ -134,11 +134,15 @@ void FpgaSetupSsc(void)
// on RX clock rising edge, sampled on falling edge // on RX clock rising edge, sampled on falling edge
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8 bits per transfer, no loopback, MSB first, 1 transfer per sync // 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync // pulse, no output sync
if ((FPGA_mode & 0xe0) == FPGA_MAJOR_MODE_HF_READER_RX_XCORR) {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
} else {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
}
// clock comes from TK pin, no clock output, outputs change on falling // TX clock comes from TK pin, no clock output, outputs change on falling
// edge of TK, sample on rising edge of TK, start on positive-going edge of sync // edge of TK, sample on rising edge of TK, start on positive-going edge of sync
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
@ -154,16 +158,15 @@ void FpgaSetupSsc(void)
// ourselves, not to another buffer). The stuff to manipulate those buffers // ourselves, not to another buffer). The stuff to manipulate those buffers
// is in apps.h, because it should be inlined, for speed. // is in apps.h, because it should be inlined, for speed.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool FpgaSetupSscDma(uint8_t *buf, int len) bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count)
{ {
if (buf == NULL) return false; if (buf == NULL) return false;
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address
AT91C_BASE_PDC_SSC->PDC_RCR = len; // transfer this many bytes AT91C_BASE_PDC_SSC->PDC_RCR = sample_count; // transfer this many samples
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address
AT91C_BASE_PDC_SSC->PDC_RNCR = len; // ... with same number of bytes AT91C_BASE_PDC_SSC->PDC_RNCR = sample_count; // ... with same number of samples AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
return true; return true;
} }

View file

@ -19,9 +19,9 @@
void FpgaSendCommand(uint16_t cmd, uint16_t v); void FpgaSendCommand(uint16_t cmd, uint16_t v);
void FpgaWriteConfWord(uint8_t v); void FpgaWriteConfWord(uint8_t v);
void FpgaDownloadAndGo(int bitstream_version); void FpgaDownloadAndGo(int bitstream_version);
void FpgaSetupSsc(void); void FpgaSetupSsc(uint8_t mode);
void SetupSpi(int mode); void SetupSpi(int mode);
bool FpgaSetupSscDma(uint8_t *buf, int len); bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count);
void Fpga_print_status(); void Fpga_print_status();
int FpgaGetCurrent(); int FpgaGetCurrent();
#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; #define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;

View file

@ -37,7 +37,7 @@ void HfSnoop(int samplesToSkip, int triggersToSkip)
// Select correct configs // Select correct configs
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port // Set up the synchronous serial port
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SNOOP);
// connect Demodulated Signal to ADC: // connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP);

View file

@ -676,7 +676,7 @@ void RAMFUNC SnoopIClass(void)
Demod.state = DEMOD_UNSYNCD; Demod.state = DEMOD_UNSYNCD;
// Setup for the DMA. // Setup for the DMA.
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
upTo = dmaBuf; upTo = dmaBuf;
lastRxCounter = DMA_BUFFER_SIZE; lastRxCounter = DMA_BUFFER_SIZE;
FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE); FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE);
@ -1163,7 +1163,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
StartCountSspClk(); StartCountSspClk();
// We need to listen to the high-frequency, peak-detected path. // We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
// To control where we are in the protocol // To control where we are in the protocol
int cmdsRecvd = 0; int cmdsRecvd = 0;
@ -1360,7 +1360,7 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K_8BIT); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K_8BIT);
AT91C_BASE_SSC->SSC_THR = 0x00; AT91C_BASE_SSC->SSC_THR = 0x00;
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
while(!BUTTON_PRESS()) { while(!BUTTON_PRESS()) {
if((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){ if((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){
b = AT91C_BASE_SSC->SSC_RHR; (void) b; b = AT91C_BASE_SSC->SSC_RHR; (void) b;
@ -1398,7 +1398,7 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int
int c; int c;
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
AT91C_BASE_SSC->SSC_THR = 0x00; AT91C_BASE_SSC->SSC_THR = 0x00;
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
if (wait) if (wait)
{ {
@ -1586,7 +1586,7 @@ void setupIclassReader()
clear_trace(); clear_trace();
// Setup SSC // Setup SSC
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
// Start from off (no field generated) // Start from off (no field generated)
// Signal field is off with the appropriate LED // Signal field is off with the appropriate LED
LED_D_OFF(); LED_D_OFF();

View file

@ -1889,7 +1889,7 @@ int iso14443a_select_card(byte_t *uid_ptr, iso14a_card_select_t *p_hi14a_card, u
void iso14443a_setup(uint8_t fpga_minor_mode) { void iso14443a_setup(uint8_t fpga_minor_mode) {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port // Set up the synchronous serial port
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
// connect Demodulated Signal to ADC: // connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);

View file

@ -1,5 +1,6 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Jonathan Westhues, split Nov 2006 // Jonathan Westhues, split Nov 2006
// piwi 2018
// //
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of // at your option, any later version. See the LICENSE.txt file for the text of
@ -16,8 +17,8 @@
#include "iso14443crc.h" #include "iso14443crc.h"
#define RECEIVE_SAMPLES_TIMEOUT 2000 #define RECEIVE_SAMPLES_TIMEOUT 1000 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA. 1000 seems to be much too high?
#define ISO14443B_DMA_BUFFER_SIZE 256 #define ISO14443B_DMA_BUFFER_SIZE 128
// PCB Block number for APDUs // PCB Block number for APDUs
static uint8_t pcb_blocknum = 0; static uint8_t pcb_blocknum = 0;
@ -374,7 +375,7 @@ void SimulateIso14443bTag(void)
// We need to listen to the high-frequency, peak-detected path. // We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
cmdsRecvd = 0; cmdsRecvd = 0;
@ -440,7 +441,7 @@ void SimulateIso14443bTag(void)
LED_D_OFF(); LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);
AT91C_BASE_SSC->SSC_THR = 0xff; AT91C_BASE_SSC->SSC_THR = 0xff;
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
// Transmit the response. // Transmit the response.
uint16_t i = 0; uint16_t i = 0;
@ -535,60 +536,11 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
#define SUBCARRIER_DETECT_THRESHOLD 8 #define SUBCARRIER_DETECT_THRESHOLD 8
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(cq)
/* #define CHECK_FOR_SUBCARRIER() { \
v = ci; \
if(v < 0) v = -v; \
if(cq > 0) { \
v += cq; \
} else { \
v -= cq; \
} \
}
*/
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
#define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2))
//note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow
#define CHECK_FOR_SUBCARRIER() { \
v = MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2); \
}
/*
if(ci < 0) { \
if(cq < 0) { \ // ci < 0, cq < 0
if (cq < ci) { \
v = -cq - (ci >> 1); \
} else { \
v = -ci - (cq >> 1); \
} \
} else { \ // ci < 0, cq >= 0
if (cq < -ci) { \
v = -ci + (cq >> 1); \
} else { \
v = cq - (ci >> 1); \
} \
} \
} else { \
if(cq < 0) { \ // ci >= 0, cq < 0
if (-cq < ci) { \
v = ci - (cq >> 1); \
} else { \
v = -cq + (ci >> 1); \
} \
} else { \ // ci >= 0, cq >= 0
if (cq < ci) { \
v = ci + (cq >> 1); \
} else { \
v = cq + (ci >> 1); \
} \
} \
} \
}
*/
switch(Demod.state) { switch(Demod.state) {
case DEMOD_UNSYNCD: case DEMOD_UNSYNCD:
CHECK_FOR_SUBCARRIER(); if(AMPLITUDE(ci,cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
if(v > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
Demod.state = DEMOD_PHASE_REF_TRAINING; Demod.state = DEMOD_PHASE_REF_TRAINING;
Demod.sumI = ci; Demod.sumI = ci;
Demod.sumQ = cq; Demod.sumQ = cq;
@ -598,8 +550,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
case DEMOD_PHASE_REF_TRAINING: case DEMOD_PHASE_REF_TRAINING:
if(Demod.posCount < 8) { if(Demod.posCount < 8) {
CHECK_FOR_SUBCARRIER(); if (AMPLITUDE(ci,cq) > SUBCARRIER_DETECT_THRESHOLD) {
if (v > SUBCARRIER_DETECT_THRESHOLD) {
// set the reference phase (will code a logic '1') by averaging over 32 1/fs. // set the reference phase (will code a logic '1') by averaging over 32 1/fs.
// note: synchronization time > 80 1/fs // note: synchronization time > 80 1/fs
Demod.sumI += ci; Demod.sumI += ci;
@ -743,9 +694,10 @@ static void DemodInit(uint8_t *data)
*/ */
static void GetSamplesFor14443bDemod(int n, bool quiet) static void GetSamplesFor14443bDemod(int n, bool quiet)
{ {
int max = 0; int maxBehindBy = 0;
bool gotFrame = false; bool gotFrame = false;
int lastRxCounter, ci, cq, samples = 0; int lastRxCounter, samples = 0;
int8_t ci, cq;
// Allocate memory from BigBuf for some buffers // Allocate memory from BigBuf for some buffers
// free all previous allocations first // free all previous allocations first
@ -755,15 +707,19 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE); uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE);
// The DMA buffer, used to stream samples from the FPGA // The DMA buffer, used to stream samples from the FPGA
int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t));
// Set up the demodulator for tag -> reader responses. // Set up the demodulator for tag -> reader responses.
DemodInit(receivedResponse); DemodInit(receivedResponse);
// wait for last transfer to complete
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY))
// Setup and start DMA. // Setup and start DMA.
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
int8_t *upTo = dmaBuf; uint16_t *upTo = dmaBuf;
lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
// Signal field is ON with the appropriate LED: // Signal field is ON with the appropriate LED:
@ -772,39 +728,40 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
for(;;) { for(;;) {
int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR; int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1);
if(behindBy > max) max = behindBy; if(behindBy > maxBehindBy) {
maxBehindBy = behindBy;
while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1)) > 2) {
ci = upTo[0];
cq = upTo[1];
upTo += 2;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) {
upTo = dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE;
} }
lastRxCounter -= 2;
if(lastRxCounter <= 0) { if(behindBy < 1) continue;
ci = *upTo >> 8;
cq = *upTo;
upTo++;
lastRxCounter--;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content.
upTo = dmaBuf; // start reading the circular buffer from the beginning
lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
} }
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated.
samples += 2; AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers
}
samples++;
if(Handle14443bSamplesDemod(ci, cq)) { if(Handle14443bSamplesDemod(ci, cq)) {
gotFrame = true; gotFrame = true;
break; break;
} }
}
if(samples > n || gotFrame) { if(samples > n) {
break; break;
} }
} }
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; FpgaDisableSscDma();
if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", max, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ); if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", maxBehindBy, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ);
//Tracing //Tracing
if (tracing && Demod.len > 0) { if (tracing && Demod.len > 0) {
uint8_t parity[MAX_PARITY_SIZE]; uint8_t parity[MAX_PARITY_SIZE];
@ -820,11 +777,7 @@ static void TransmitFor14443b(void)
{ {
int c; int c;
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0xff;
}
// Signal field is ON with the appropriate Red LED // Signal field is ON with the appropriate Red LED
LED_D_ON(); LED_D_ON();
@ -832,31 +785,15 @@ static void TransmitFor14443b(void)
LED_B_ON(); LED_B_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
for(c = 0; c < 10;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0xff;
c++;
}
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
(void)r;
}
WDT_HIT();
}
c = 0; c = 0;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = ToSend[c]; AT91C_BASE_SSC->SSC_THR = ~ToSend[c];
c++; c++;
if(c >= ToSendMax) { if(c >= ToSendMax) {
break; break;
} }
} }
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
(void)r;
}
WDT_HIT(); WDT_HIT();
} }
LED_B_OFF(); // Finished sending LED_B_OFF(); // Finished sending
@ -874,19 +811,14 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
ToSendReset(); ToSendReset();
// Establish initial reference level
for(i = 0; i < 40; i++) {
ToSendStuffBit(1);
}
// Send SOF // Send SOF
for(i = 0; i < 10; i++) { for(i = 0; i < 10; i++) {
ToSendStuffBit(0); ToSendStuffBit(0);
} }
ToSendStuffBit(1);
ToSendStuffBit(1);
for(i = 0; i < len; i++) { for(i = 0; i < len; i++) {
// Stop bits/EGT
ToSendStuffBit(1);
ToSendStuffBit(1);
// Start bit // Start bit
ToSendStuffBit(0); ToSendStuffBit(0);
// Data bits // Data bits
@ -899,19 +831,18 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
} }
b >>= 1; b >>= 1;
} }
} // Stop bit
// Send EOF
ToSendStuffBit(1);
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
}
for(i = 0; i < 8; i++) {
ToSendStuffBit(1); ToSendStuffBit(1);
} }
// And then a little more, to make sure that the last character makes // Send EOF
// it out before we switch to rx mode. for(i = 0; i < 10; i++) {
for(i = 0; i < 24; i++) { ToSendStuffBit(0);
}
ToSendStuffBit(1);
// ensure that last byte is filled up
for(i = 0; i < 8; i++) {
ToSendStuffBit(1); ToSendStuffBit(1);
} }
@ -951,7 +882,7 @@ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *respo
// send // send
CodeAndTransmit14443bAsReader(message_frame, message_length + 4); CodeAndTransmit14443bAsReader(message_frame, message_length + 4);
// get response // get response
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT*100, true); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if(Demod.len < 3) if(Demod.len < 3)
{ {
return 0; return 0;
@ -1011,7 +942,7 @@ int iso14443b_select_card()
void iso14443b_setup() { void iso14443b_setup() {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port // Set up the synchronous serial port
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
// connect Demodulated Signal to ADC: // connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
@ -1019,9 +950,6 @@ void iso14443b_setup() {
LED_D_ON(); LED_D_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
// Start the timer
StartCountSspClk();
DemodReset(); DemodReset();
UartReset(); UartReset();
} }
@ -1047,7 +975,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
SpinDelay(200); SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Now give it time to spin up. // Now give it time to spin up.
// Signal field is on with the appropriate LED // Signal field is on with the appropriate LED
@ -1065,6 +993,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
if (Demod.len == 0) { if (Demod.len == 0) {
DbpString("No response from tag"); DbpString("No response from tag");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} else { } else {
Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x", Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x",
@ -1080,17 +1010,23 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 3) { if (Demod.len != 3) {
Dbprintf("Expected 3 bytes from tag, got %d", Demod.len); Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
// Check the CRC of the answer: // Check the CRC of the answer:
ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]); ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);
if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) { if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {
DbpString("CRC Error reading select response."); DbpString("CRC Error reading select response.");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
// Check response from the tag: should be the same UID as the command we just sent: // Check response from the tag: should be the same UID as the command we just sent:
if (cmd1[1] != Demod.output[0]) { if (cmd1[1] != Demod.output[0]) {
Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]); Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
@ -1102,6 +1038,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 10) { if (Demod.len != 10) {
Dbprintf("Expected 10 bytes from tag, got %d", Demod.len); Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
// The check the CRC of the answer (use cmd1 as temporary variable): // The check the CRC of the answer (use cmd1 as temporary variable):
@ -1131,6 +1069,8 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true); GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 6) { // Check if we got an answer from the tag if (Demod.len != 6) { // Check if we got an answer from the tag
DbpString("Expected 6 bytes from tag, got less..."); DbpString("Expected 6 bytes from tag, got less...");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return; return;
} }
// The check the CRC of the answer (use cmd1 as temporary variable): // The check the CRC of the answer (use cmd1 as temporary variable):
@ -1149,6 +1089,9 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
} }
i++; i++;
} }
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
} }
@ -1171,11 +1114,6 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
*/ */
void RAMFUNC SnoopIso14443b(void) void RAMFUNC SnoopIso14443b(void)
{ {
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
int triggered = true; // TODO: set and evaluate trigger condition
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
BigBuf_free(); BigBuf_free();
@ -1183,10 +1121,10 @@ void RAMFUNC SnoopIso14443b(void)
set_tracing(true); set_tracing(true);
// The DMA buffer, used to stream samples from the FPGA // The DMA buffer, used to stream samples from the FPGA
int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE); uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t));
int lastRxCounter; int lastRxCounter;
int8_t *upTo; uint16_t *upTo;
int ci, cq; int8_t ci, cq;
int maxBehindBy = 0; int maxBehindBy = 0;
// Count of samples received so far, so that we can include timing // Count of samples received so far, so that we can include timing
@ -1211,7 +1149,7 @@ void RAMFUNC SnoopIso14443b(void)
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Setup for the DMA. // Setup for the DMA.
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
upTo = dmaBuf; upTo = dmaBuf;
lastRxCounter = ISO14443B_DMA_BUFFER_SIZE; lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE); FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
@ -1219,46 +1157,48 @@ void RAMFUNC SnoopIso14443b(void)
bool TagIsActive = false; bool TagIsActive = false;
bool ReaderIsActive = false; bool ReaderIsActive = false;
// We won't start recording the frames that we acquire until we trigger.
// A good trigger condition to get started is probably when we see a
// reader command
bool triggered = false;
// And now we loop, receiving samples. // And now we loop, receiving samples.
for(;;) { for(;;) {
int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1);
(ISO14443B_DMA_BUFFER_SIZE-1);
if(behindBy > maxBehindBy) { if(behindBy > maxBehindBy) {
maxBehindBy = behindBy; maxBehindBy = behindBy;
} }
if(behindBy < 2) continue; if(behindBy < 1) continue;
ci = upTo[0]; ci = *upTo>>8;
cq = upTo[1]; cq = *upTo;
upTo += 2; upTo++;
lastRxCounter -= 2; lastRxCounter--;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content.
upTo = dmaBuf; upTo = dmaBuf; // start reading the circular buffer from the beginning again
lastRxCounter += ISO14443B_DMA_BUFFER_SIZE; lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) {
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy);
break;
}
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated.
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers
WDT_HIT(); WDT_HIT();
if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not?
Dbprintf("blew circular buffer! behindBy=%d", behindBy);
break;
}
if(!tracing) {
DbpString("Reached trace limit");
break;
}
if(BUTTON_PRESS()) { if(BUTTON_PRESS()) {
DbpString("cancelled"); DbpString("cancelled");
break; break;
} }
} }
samples += 2; samples++;
if (!TagIsActive) { // no need to try decoding reader data if the tag is sending if (!TagIsActive) { // no need to try decoding reader data if the tag is sending
if(Handle14443bUartBit(ci & 0x01)) { if(Handle14443bUartBit(ci & 0x01)) {
if(triggered && tracing) { triggered = true;
if(tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true); LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
} }
/* And ready to receive another command. */ /* And ready to receive another command. */
@ -1268,7 +1208,8 @@ void RAMFUNC SnoopIso14443b(void)
DemodReset(); DemodReset();
} }
if(Handle14443bUartBit(cq & 0x01)) { if(Handle14443bUartBit(cq & 0x01)) {
if(triggered && tracing) { triggered = true;
if(tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true); LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
} }
/* And ready to receive another command. */ /* And ready to receive another command. */
@ -1280,8 +1221,8 @@ void RAMFUNC SnoopIso14443b(void)
ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF); ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF);
} }
if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time if(!ReaderIsActive && triggered) { // no need to try decoding tag data if the reader is sending or not yet triggered
if(Handle14443bSamplesDemod(ci | 0x01, cq | 0x01)) { if(Handle14443bSamplesDemod(ci/2, cq/2)) {
//Use samples as a time measurement //Use samples as a time measurement
if(tracing) if(tracing)
@ -1289,8 +1230,6 @@ void RAMFUNC SnoopIso14443b(void)
uint8_t parity[MAX_PARITY_SIZE]; uint8_t parity[MAX_PARITY_SIZE];
LogTrace(Demod.output, Demod.len, samples, samples, parity, false); LogTrace(Demod.output, Demod.len, samples, samples, parity, false);
} }
triggered = true;
// And ready to receive another response. // And ready to receive another response.
DemodReset(); DemodReset();
} }
@ -1301,7 +1240,6 @@ void RAMFUNC SnoopIso14443b(void)
FpgaDisableSscDma(); FpgaDisableSscDma();
LEDsoff(); LEDsoff();
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
DbpString("Snoop statistics:"); DbpString("Snoop statistics:");
Dbprintf(" Max behind by: %i", maxBehindBy); Dbprintf(" Max behind by: %i", maxBehindBy);
Dbprintf(" Uart State: %x", Uart.state); Dbprintf(" Uart State: %x", Uart.state);
@ -1327,7 +1265,11 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u
{ {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
// switch field on and give tag some time to power up
LED_D_ON();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
SpinDelay(10);
if (datalen){ if (datalen){
set_tracing(true); set_tracing(true);

View file

@ -227,26 +227,14 @@ static void TransmitTo15693Tag(const uint8_t *cmd, int len, int *samples, int *w
{ {
int c; int c;
// FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
if(*wait < 10) { *wait = 10; } if(*wait < 10) { *wait = 10; }
// for(c = 0; c < *wait;) {
// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
// AT91C_BASE_SSC->SSC_THR = 0x00; // For exact timing!
// c++;
// }
// if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
// volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
// (void)r;
// }
// WDT_HIT();
// }
c = 0; c = 0;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = cmd[c]; AT91C_BASE_SSC->SSC_THR = ~cmd[c];
c++; c++;
if(c >= len) { if(c >= len) {
break; break;
@ -300,36 +288,25 @@ static int GetIso15693AnswerFromTag(uint8_t *receivedResponse, int maxLen, int *
{ {
int c = 0; int c = 0;
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
int getNext = 0;
int8_t prev = 0;
// NOW READ RESPONSE // NOW READ RESPONSE
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
c = 0; c = 0;
getNext = false;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b; uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the // The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I, // tone that the tag AM-modulates. We just want power.
// every other is Q. We just want power, so abs(I) + abs(Q) is int8_t i = iq >> 8;
// close to what we want. int8_t q = iq;
if(getNext) { uint8_t r = AMPLITUDE(i, q);
uint8_t r = AMPLITUDE(b, prev);
dest[c++] = r; dest[c++] = r;
if(c >= 4000) { if(c >= 4000) {
break; break;
} }
} else {
prev = b;
}
getNext = !getNext;
} }
} }
@ -441,36 +418,26 @@ static int GetIso15693AnswerFromSniff(uint8_t *receivedResponse, int maxLen, int
{ {
int c = 0; int c = 0;
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
int getNext = 0;
int8_t prev = 0;
// NOW READ RESPONSE // NOW READ RESPONSE
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
//spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads //spindelay(60); // greg - experiment to get rid of some of the 0 byte/failed reads
c = 0; c = 0;
getNext = false;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b = (int8_t)AT91C_BASE_SSC->SSC_RHR; uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the // The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I, // tone that the tag AM-modulates. We just want power,
// every other is Q. We just want power, so abs(I) + abs(Q) is // so abs(I) + abs(Q) is close to what we want.
// close to what we want. int8_t i = iq >> 8;
if(getNext) { int8_t q = iq;
uint8_t r = AMPLITUDE(b, prev); uint8_t r = AMPLITUDE(i, q);
dest[c++] = r; dest[c++] = r;
if(c >= BIGBUF_SIZE) { if(c >= BIGBUF_SIZE) {
break; break;
} }
} else {
prev = b;
}
getNext = !getNext;
} }
} }
@ -585,8 +552,6 @@ void AcquireRawAdcSamplesIso15693(void)
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
int c = 0; int c = 0;
int getNext = 0;
int8_t prev = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
BuildIdentifyRequest(); BuildIdentifyRequest();
@ -598,13 +563,13 @@ void AcquireRawAdcSamplesIso15693(void)
SpinDelay(100); SpinDelay(100);
// Now send the command // Now send the command
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
c = 0; c = 0;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = ToSend[c]; AT91C_BASE_SSC->SSC_THR = ~ToSend[c];
c++; c++;
if(c == ToSendMax+3) { if(c == ToSendMax+3) {
break; break;
@ -613,32 +578,25 @@ void AcquireRawAdcSamplesIso15693(void)
WDT_HIT(); WDT_HIT();
} }
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
c = 0; c = 0;
getNext = false;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b; uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the // The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I, // tone that the tag AM-modulates. We just want power,
// every other is Q. We just want power, so abs(I) + abs(Q) is // so abs(I) + abs(Q) is close to what we want.
// close to what we want. int8_t i = iq >> 8;
if(getNext) { int8_t q = iq;
uint8_t r = AMPLITUDE(b, prev); uint8_t r = AMPLITUDE(i, q);
dest[c++] = r; dest[c++] = r;
if(c >= 4000) { if(c >= 4000) {
break; break;
} }
} else {
prev = b;
}
getNext = !getNext;
} }
} }
} }
@ -649,12 +607,10 @@ void RecordRawAdcSamplesIso15693(void)
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
int c = 0; int c = 0;
int getNext = 0;
int8_t prev = 0;
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Setup SSC // Setup SSC
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Start from off (no field generated) // Start from off (no field generated)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -667,33 +623,24 @@ void RecordRawAdcSamplesIso15693(void)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
c = 0; c = 0;
getNext = false;
for(;;) { for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
int8_t b; uint16_t iq = AT91C_BASE_SSC->SSC_RHR;
b = (int8_t)AT91C_BASE_SSC->SSC_RHR;
// The samples are correlations against I and Q versions of the // The samples are correlations against I and Q versions of the
// tone that the tag AM-modulates, so every other sample is I, // tone that the tag AM-modulates. We just want power,
// every other is Q. We just want power, so abs(I) + abs(Q) is // so abs(I) + abs(Q) is close to what we want.
// close to what we want. int8_t i = iq >> 8;
if(getNext) { int8_t q = iq;
uint8_t r = AMPLITUDE(b, prev); uint8_t r = AMPLITUDE(i, q);
dest[c++] = r; dest[c++] = r;
if(c >= 14000) { if(c >= 14000) {
break; break;
} }
} else {
prev = b;
}
getNext = !getNext;
WDT_HIT();
} }
} }
Dbprintf("fin record"); Dbprintf("finished recording");
} }
@ -714,7 +661,7 @@ void Iso15693InitReader() {
SpinDelay(10); SpinDelay(10);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Give the tags time to energize // Give the tags time to energize
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
@ -973,7 +920,7 @@ void ReaderIso15693(uint32_t parameter)
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Setup SSC // Setup SSC
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Start from off (no field generated) // Start from off (no field generated)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -1075,7 +1022,7 @@ void SimTagIso15693(uint32_t parameter, uint8_t *uid)
memset(buf, 0x00, 100); memset(buf, 0x00, 100);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Start from off (no field generated) // Start from off (no field generated)
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);

View file

@ -63,11 +63,11 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
// I/O interface abstraction (FPGA -> ARM) // I/O interface abstraction (FPGA -> ARM)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static inline uint8_t rx_byte_from_fpga() { static inline uint16_t rx_frame_from_fpga() {
for(;;) { for(;;) {
WDT_HIT(); WDT_HIT();
// wait for byte be become available in rx holding register // wait for frame be become available in rx holding register
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
return AT91C_BASE_SSC->SSC_RHR; return AT91C_BASE_SSC->SSC_RHR;
} }
@ -88,33 +88,32 @@ static inline uint8_t rx_byte_from_fpga() {
// To reduce CPU time the amplitude is approximated by using linear functions: // To reduce CPU time the amplitude is approximated by using linear functions:
// am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq)) // am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq))
// //
// Note: The SSC receiver is never synchronized the calculation my be performed
// on a I/Q pair from two subsequent correlations, but does not matter.
//
// The bit time is 99.1us (21 I/Q pairs). The receiver skips the first 5 samples // The bit time is 99.1us (21 I/Q pairs). The receiver skips the first 5 samples
// and averages the next (most stable) 8 samples. The final 8 samples are dropped // and averages the next (most stable) 8 samples. The final 8 samples are dropped
// also. // also.
// //
// The demedulated should be alligned to the bit periode by the caller. This is // The demodulated should be alligned to the bit period by the caller. This is
// done in rx_bit and rx_ack. // done in rx_bit and rx_ack.
static inline bool rx_bit() { static inline bool rx_bit() {
int32_t cq = 0; int32_t sum_cq = 0;
int32_t ci = 0; int32_t sum_ci = 0;
// skip first 5 I/Q pairs // skip first 5 I/Q pairs
for(size_t i = 0; i<5; ++i) { for(size_t i = 0; i<5; ++i) {
(int8_t)rx_byte_from_fpga(); (void)rx_frame_from_fpga();
(int8_t)rx_byte_from_fpga();
} }
// sample next 8 I/Q pairs // sample next 8 I/Q pairs
for(size_t i = 0; i<8; ++i) { for(size_t i = 0; i<8; ++i) {
cq += (int8_t)rx_byte_from_fpga(); uint16_t iq = rx_frame_from_fpga();
ci += (int8_t)rx_byte_from_fpga(); int8_t ci = (int8_t)(iq >> 8);
int8_t cq = (int8_t)(iq & 0xff);
sum_ci += ci;
sum_cq += cq;
} }
// calculate power // calculate power
int32_t power = (MAX(ABS(ci), ABS(cq)) + (MIN(ABS(ci), ABS(cq)) >> 1)); int32_t power = (MAX(ABS(sum_ci), ABS(sum_cq)) + MIN(ABS(sum_ci), ABS(sum_cq))/2);
// compare average (power / 8) to threshold // compare average (power / 8) to threshold
return ((power >> 3) > INPUT_THRESHOLD); return ((power >> 3) > INPUT_THRESHOLD);
@ -131,12 +130,12 @@ static inline bool rx_bit() {
static inline void tx_bit(bool bit) { static inline void tx_bit(bool bit) {
// insert pause // insert pause
LOW(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE; last_frame_end += RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { }; while(GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT);
// return to high, wait for bit periode to end // return to carrier on, wait for bit periode to end
LOW(GPIO_SSC_DOUT);
last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE; last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { }; while(GET_TICKS < last_frame_end) { };
} }
@ -166,10 +165,10 @@ static void tx_frame(uint32_t frame, uint8_t len) {
}; };
// add pause to mark end of the frame // add pause to mark end of the frame
LOW(GPIO_SSC_DOUT); HIGH(GPIO_SSC_DOUT);
last_frame_end += RWD_TIME_PAUSE; last_frame_end += RWD_TIME_PAUSE;
while(GET_TICKS < last_frame_end) { }; while(GET_TICKS < last_frame_end) { };
HIGH(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
} }
static uint32_t rx_frame(uint8_t len) { static uint32_t rx_frame(uint8_t len) {
@ -265,12 +264,12 @@ static void init_reader(bool clear_mem) {
LED_D_ON(); LED_D_ON();
// configure SSC with defaults // configure SSC with defaults
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// re-claim GPIO_SSC_DOUT as GPIO and enable output // re-claim GPIO_SSC_DOUT as GPIO and enable output
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
HIGH(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);
// init crc calculator // init crc calculator
crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0); crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0);

View file

@ -284,7 +284,7 @@ static void init_tag() {
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// configure SSC with defaults // configure SSC with defaults
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
// first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT // first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT
LOW(GPIO_SSC_DOUT); LOW(GPIO_SSC_DOUT);

View file

@ -1849,7 +1849,7 @@ void Cotag(uint32_t arg0) {
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Now set up the SSC to get the ADC samples that are now streaming at us. // Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC);
// start clock - 1.5ticks is 1us // start clock - 1.5ticks is 1us
StartTicks(); StartTicks();

View file

@ -101,7 +101,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
// Give it a bit of time for the resonant antenna to settle. // Give it a bit of time for the resonant antenna to settle.
SpinDelay(50); SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us. // Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc(); FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC);
} }
/** /**

View file

@ -81,11 +81,6 @@ void lsl (uint8_t *data, size_t len) {
data[len - 1] <<= 1; data[len - 1] <<= 1;
} }
int32_t le24toh (uint8_t data[3])
{
return (data[2] << 16) | (data[1] << 8) | data[0];
}
void LEDsoff() void LEDsoff()
{ {
LED_A_OFF(); LED_A_OFF();

View file

@ -34,7 +34,6 @@ void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len); uint64_t bytes_to_num(uint8_t* src, size_t len);
void rol(uint8_t *data, const size_t len); void rol(uint8_t *data, const size_t len);
void lsl (uint8_t *data, size_t len); void lsl (uint8_t *data, size_t len);
int32_t le24toh (uint8_t data[3]);
void LED(int led, int ms); void LED(int led, int ms);
void LEDsoff(); void LEDsoff();

View file

@ -19,8 +19,10 @@ OBJDIR = obj
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
LUALIB = ../liblua/liblua.a LUALIB = ../liblua/liblua.a
JANSSONLIBPATH = ./jansson
JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a
LDFLAGS = $(ENV_LDFLAGS) LDFLAGS = $(ENV_LDFLAGS)
CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3 CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -I$(JANSSONLIBPATH) -Wall -g -O3
CXXFLAGS = -I../include -Wall -O3 CXXFLAGS = -I../include -Wall -O3
APP_CFLAGS = APP_CFLAGS =
@ -236,12 +238,12 @@ WINBINS = $(patsubst %, %.exe, $(BINS))
CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h
# need to assign dependancies to build these first... # need to assign dependancies to build these first...
all: lua_build $(BINS) all: lua_build jansson_build $(BINS)
all-static: LDLIBS:=-static $(LDLIBS) all-static: LDLIBS:=-static $(LDLIBS)
all-static: proxmark3 flasher fpga_compress all-static: proxmark3 flasher fpga_compress
proxmark3: LDLIBS+=$(LUALIB) $(QTLDLIBS) proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(QTLDLIBS)
proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua
$(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@ $(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@
@ -265,6 +267,7 @@ lualibs/usb_cmd.lua: ../include/usb_cmd.h
clean: clean:
$(RM) $(CLEAN) $(RM) $(CLEAN)
cd ../liblua && make clean cd ../liblua && make clean
cd ./jansson && make clean
tarbin: $(BINS) tarbin: $(BINS)
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%) $(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%)
@ -273,6 +276,10 @@ lua_build:
@echo Compiling liblua, using platform $(LUAPLATFORM) @echo Compiling liblua, using platform $(LUAPLATFORM)
cd ../liblua && make $(LUAPLATFORM) cd ../liblua && make $(LUAPLATFORM)
jansson_build:
@echo Compiling jansson
cd ./jansson && make all
.PHONY: all clean .PHONY: all clean
$(OBJDIR)/%_NOSIMD.o : %.c $(OBJDIR)/%.d $(OBJDIR)/%_NOSIMD.o : %.c $(OBJDIR)/%.d

View file

@ -11,6 +11,7 @@
#include <ctype.h> #include <ctype.h>
#include "cmdemv.h" #include "cmdemv.h"
#include "test/cryptotest.h" #include "test/cryptotest.h"
#include <jansson.h>
int UsageCmdHFEMVSelect(void) { int UsageCmdHFEMVSelect(void) {
PrintAndLog("HELP : Executes select applet command:\n"); PrintAndLog("HELP : Executes select applet command:\n");
@ -279,11 +280,12 @@ int CmdHFEMVPPSE(const char *cmd) {
int UsageCmdHFEMVExec(void) { int UsageCmdHFEMVExec(void) {
PrintAndLog("HELP : Executes EMV contactless transaction:\n"); PrintAndLog("HELP : Executes EMV contactless transaction:\n");
PrintAndLog("Usage: hf emv exec [-s][-a][-t][-f][-v][-c][-x][-g]\n"); PrintAndLog("Usage: hf emv exec [-s][-a][-t][-j][-f][-v][-c][-x][-g]\n");
PrintAndLog(" Options:"); PrintAndLog(" Options:");
PrintAndLog(" -s : select card"); PrintAndLog(" -s : select card");
PrintAndLog(" -a : show APDU reqests and responses\n"); PrintAndLog(" -a : show APDU reqests and responses\n");
PrintAndLog(" -t : TLV decode results\n"); PrintAndLog(" -t : TLV decode results\n");
PrintAndLog(" -j : load transaction parameters from `emv/defparams.json` file\n");
PrintAndLog(" -f : force search AID. Search AID instead of execute PPSE.\n"); PrintAndLog(" -f : force search AID. Search AID instead of execute PPSE.\n");
PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n"); PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n"); PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
@ -296,9 +298,159 @@ int UsageCmdHFEMVExec(void) {
return 0; return 0;
} }
#define TLV_ADD(tag, value)( tlvdb_add(tlvRoot, tlvdb_fixed(tag, sizeof(value) - 1, (const unsigned char *)value)) ) #define TLV_ADD(tag, value)( tlvdb_change_or_add_node(tlvRoot, tag, sizeof(value) - 1, (const unsigned char *)value) )
#define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;} #define dreturn(n) {free(pdol_data_tlv);tlvdb_free(tlvSelect);tlvdb_free(tlvRoot);DropField();return n;}
bool HexToBuffer(const char *errormsg, const char *hexvalue, uint8_t * buffer, size_t maxbufferlen, size_t *bufferlen) {
int buflen = 0;
switch(param_gethex_to_eol(hexvalue, 0, buffer, maxbufferlen, &buflen)) {
case 1:
PrintAndLog("%s Invalid HEX value.", errormsg);
return false;
case 2:
PrintAndLog("%s Hex value too large.", errormsg);
return false;
case 3:
PrintAndLog("%s Hex value must have even number of digits.", errormsg);
return false;
}
if (buflen > maxbufferlen) {
PrintAndLog("%s HEX length (%d) more than %d", errormsg, *bufferlen, maxbufferlen);
return false;
}
*bufferlen = buflen;
return true;
}
bool ParamLoadFromJson(struct tlvdb *tlv) {
json_t *root;
json_error_t error;
if (!tlv) {
PrintAndLog("ERROR load params: tlv tree is NULL.");
return false;
}
// current path + file name
const char *relfname = "emv/defparams.json";
char fname[strlen(get_my_executable_directory()) + strlen(relfname) + 1];
strcpy(fname, get_my_executable_directory());
strcat(fname, relfname);
root = json_load_file(fname, 0, &error);
if (!root) {
PrintAndLog("Load params: json error on line %d: %s", error.line, error.text);
return false;
}
if (!json_is_array(root)) {
PrintAndLog("Load params: Invalid json format. root must be array.");
return false;
}
PrintAndLog("Load params: json OK");
for(int i = 0; i < json_array_size(root); i++) {
json_t *data, *jtype, *jlength, *jvalue;
data = json_array_get(root, i);
if(!json_is_object(data))
{
PrintAndLog("Load params: data [%d] is not an object", i + 1);
json_decref(root);
return false;
}
jtype = json_object_get(data, "type");
if(!json_is_string(jtype))
{
PrintAndLog("Load params: data [%d] type is not a string", i + 1);
json_decref(root);
return false;
}
const char *tlvType = json_string_value(jtype);
jvalue = json_object_get(data, "value");
if(!json_is_string(jvalue))
{
PrintAndLog("Load params: data [%d] value is not a string", i + 1);
json_decref(root);
return false;
}
const char *tlvValue = json_string_value(jvalue);
jlength = json_object_get(data, "length");
if(!json_is_number(jlength))
{
PrintAndLog("Load params: data [%d] length is not a number", i + 1);
json_decref(root);
return false;
}
int tlvLength = json_integer_value(jlength);
if (tlvLength > 250) {
PrintAndLog("Load params: data [%d] length more than 250", i + 1);
json_decref(root);
return false;
}
PrintAndLog("TLV param: %s[%d]=%s", tlvType, tlvLength, tlvValue);
uint8_t buf[251] = {0};
size_t buflen = 0;
// here max length must be 4, but now tlv_tag_t is 2-byte var. so let it be 2 by now... TODO: needs refactoring tlv_tag_t...
if (!HexToBuffer("TLV Error type:", tlvType, buf, 2, &buflen)) {
json_decref(root);
return false;
}
tlv_tag_t tag = 0;
for (int i = 0; i < buflen; i++) {
tag = (tag << 8) + buf[i];
}
if (!HexToBuffer("TLV Error value:", tlvValue, buf, sizeof(buf) - 1, &buflen)) {
json_decref(root);
return false;
}
if (buflen != tlvLength) {
PrintAndLog("Load params: data [%d] length of HEX must(%d) be identical to length in TLV param(%d)", i + 1, buflen, tlvLength);
json_decref(root);
return false;
}
tlvdb_change_or_add_node(tlv, tag, tlvLength, (const unsigned char *)buf);
}
json_decref(root);
return true;
}
void ParamLoadDefaults(struct tlvdb *tlvRoot) {
//9F02:(Amount, authorized (Numeric)) len:6
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
//9F1A:(Terminal Country Code) len:2
TLV_ADD(0x9F1A, "ru");
//5F2A:(Transaction Currency Code) len:2
// USD 840, EUR 978, RUR 810, RUB 643, RUR 810(old), UAH 980, AZN 031, n/a 999
TLV_ADD(0x5F2A, "\x09\x80");
//9A:(Transaction Date) len:3
TLV_ADD(0x9A, "\x00\x00\x00");
//9C:(Transaction Type) len:1 | 00 => Goods and service #01 => Cash
TLV_ADD(0x9C, "\x00");
// 9F37 Unpredictable Number len:4
TLV_ADD(0x9F37, "\x01\x02\x03\x04");
// 9F6A Unpredictable Number (MSD for UDOL) len:4
TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
}
int CmdHFEMVExec(const char *cmd) { int CmdHFEMVExec(const char *cmd) {
bool activateField = false; bool activateField = false;
bool showAPDU = false; bool showAPDU = false;
@ -306,6 +458,7 @@ int CmdHFEMVExec(const char *cmd) {
bool forceSearch = false; bool forceSearch = false;
enum TransactionType TrType = TT_MSD; enum TransactionType TrType = TT_MSD;
bool GenACGPO = false; bool GenACGPO = false;
bool paramLoadJSON = false;
uint8_t buf[APDU_RES_LEN] = {0}; uint8_t buf[APDU_RES_LEN] = {0};
size_t len = 0; size_t len = 0;
@ -367,6 +520,10 @@ int CmdHFEMVExec(const char *cmd) {
case 'G': case 'G':
GenACGPO = true; GenACGPO = true;
break; break;
case 'j':
case 'J':
paramLoadJSON = true;
break;
default: default:
PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp)); PrintAndLog("Unknown parameter '%c'", param_getchar_indx(cmd, 1, cmdp));
return 1; return 1;
@ -433,6 +590,13 @@ int CmdHFEMVExec(const char *cmd) {
PrintAndLog("\n* Init transaction parameters."); PrintAndLog("\n* Init transaction parameters.");
ParamLoadDefaults(tlvRoot);
if (paramLoadJSON) {
PrintAndLog("* * Transaction parameters loading from JSON...");
ParamLoadFromJson(tlvRoot);
}
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4 //9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
char *qVSDC = "\x26\x00\x00\x00"; char *qVSDC = "\x26\x00\x00\x00";
if (GenACGPO) { if (GenACGPO) {
@ -453,26 +617,9 @@ int CmdHFEMVExec(const char *cmd) {
TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled) TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
break; break;
default: default:
TLV_ADD(0x9F66, "\x26\x00\x00\x00"); // qVSDC
break; break;
} }
//9F02:(Amount, authorized (Numeric)) len:6
TLV_ADD(0x9F02, "\x00\x00\x00\x00\x01\x00");
//9F1A:(Terminal Country Code) len:2
TLV_ADD(0x9F1A, "ru");
//5F2A:(Transaction Currency Code) len:2
// USD 840, EUR 978, RUR 810, RUB 643, RUR 810(old), UAH 980, AZN 031, n/a 999
TLV_ADD(0x5F2A, "\x09\x80");
//9A:(Transaction Date) len:3
TLV_ADD(0x9A, "\x00\x00\x00");
//9C:(Transaction Type) len:1 | 00 => Goods and service #01 => Cash
TLV_ADD(0x9C, "\x00");
// 9F37 Unpredictable Number len:4
TLV_ADD(0x9F37, "\x01\x02\x03\x04");
// 9F6A Unpredictable Number (MSD for UDOL) len:4
TLV_ADD(0x9F6A, "\x01\x02\x03\x04");
TLVPrintFromTLV(tlvRoot); // TODO delete!!! TLVPrintFromTLV(tlvRoot); // TODO delete!!!
PrintAndLog("\n* Calc PDOL."); PrintAndLog("\n* Calc PDOL.");
@ -828,6 +975,30 @@ int CmdHFEMVExec(const char *cmd) {
return 0; return 0;
} }
int UsageCmdHFEMVScan(void) {
PrintAndLog("HELP : Scan EMV card and save it contents to a file. \n");
PrintAndLog(" It executes EMV contactless transaction and saves result to a file which can be used for emulation.\n");
PrintAndLog("Usage: hf emv scan [-a][-t][-v][-c][-x][-g] <file_name>\n");
PrintAndLog(" Options:");
PrintAndLog(" -a : show APDU reqests and responses\n");
PrintAndLog(" -t : TLV decode results\n");
PrintAndLog(" -v : transaction type - qVSDC or M/Chip.\n");
PrintAndLog(" -c : transaction type - qVSDC or M/Chip plus CDA (SDAD generation).\n");
PrintAndLog(" -x : transaction type - VSDC. For test only. Not a standart behavior.\n");
PrintAndLog(" -g : VISA. generate AC from GPO\n");
PrintAndLog("By default : transaction type - MSD.\n");
PrintAndLog("Samples:");
PrintAndLog(" hf emv scan -a -t -> scan MSD transaction mode");
PrintAndLog(" hf emv scan -a -t -c -> scan CDA transaction mode");
return 0;
}
int CmdHFEMVScan(const char *cmd) {
UsageCmdHFEMVScan();
return 0;
}
int CmdHFEMVTest(const char *cmd) { int CmdHFEMVTest(const char *cmd) {
return ExecuteCryptoTests(true); return ExecuteCryptoTests(true);
} }
@ -839,6 +1010,7 @@ static command_t CommandTable[] = {
{"pse", CmdHFEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."}, {"pse", CmdHFEMVPPSE, 0, "Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory."},
{"search", CmdHFEMVSearch, 0, "Try to select all applets from applets list and print installed applets."}, {"search", CmdHFEMVSearch, 0, "Try to select all applets from applets list and print installed applets."},
{"select", CmdHFEMVSelect, 0, "Select applet."}, {"select", CmdHFEMVSelect, 0, "Select applet."},
// {"scan", CmdHFEMVScan, 0, "Scan EMV card and save it contents to json file for emulator."},
{"test", CmdHFEMVTest, 0, "Crypto logic test."}, {"test", CmdHFEMVTest, 0, "Crypto logic test."},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

58
client/emv/defparams.json Normal file
View file

@ -0,0 +1,58 @@
[
{
"name": "Transaction Date",
"type": "9A",
"value": "00 00 00",
"length": 3,
"hint": "format: YYMMDD"
},
{
"name": "Transaction Type",
"type": "9C",
"value": "00",
"length": 1,
"hint": "00: Goods and service, 01: Cash"
},
{
"name": "Amount, authorized",
"type": "9F 02",
"value": "00 00 00 00 01 00",
"length": 6,
"hint": "amount (numberic) in cents"
},
{
"name": "Transaction Currency Code",
"type": "5F 2A",
"value": "09 80",
"length": 2,
"hint": "USD 840, EUR 978, RUB 643, RUR 810(old), UAH 980, AZN 031, n/a 999"
},
{
"name": "Terminal Country Code",
"type": "9F 1A",
"value": "72 75",
"length": 2,
"hint": "ISO3166: de, en (65 6e), uk(75 6b), ru (72 75), us, ua"
},
{
"name": "Terminal Transaction Qualifiers (TTQ)",
"type": "9F 66",
"value": "26 00 00 00",
"length": 4,
"hint": "qVSDC 26 00 00 00, gen AC from GPO 26 80 00 00, MSD 86 00 00 00, VSDC 46 00 00 00"
},
{
"name": "Unpredictable Number",
"type": "9F 37",
"value": "01 02 03 04",
"length": 4,
"hint": "4 byte random number"
},
{
"name": "Unpredictable Number (MSD for UDOL)",
"type": "9F 6A",
"value": "01 02 03 05",
"length": 4,
"hint": "4 byte random number"
}
]

View file

@ -272,6 +272,7 @@ static const struct emv_tag emv_tags[] = {
{ 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC }, { 0x9f6a, "Unpredictable Number", EMV_TAG_NUMERIC },
{ 0x9f6b, "Track 2 Data" }, { 0x9f6b, "Track 2 Data" },
{ 0x9f6c, "Card Transaction Qualifiers (CTQ)", EMV_TAG_BITMASK, &EMV_CTQ }, { 0x9f6c, "Card Transaction Qualifiers (CTQ)", EMV_TAG_BITMASK, &EMV_CTQ },
{ 0x9f6e, "Form Factor Indicator" },
{ 0xa5 , "File Control Information (FCI) Proprietary Template" }, { 0xa5 , "File Control Information (FCI) Proprietary Template" },
{ 0xbf0c, "File Control Information (FCI) Issuer Discretionary Data" }, { 0xbf0c, "File Control Information (FCI) Issuer Discretionary Data" },
{ 0xdf20, "Issuer Proprietary Bitmap (IPB)" }, { 0xdf20, "Issuer Proprietary Bitmap (IPB)" },

View file

@ -318,6 +318,24 @@ struct tlvdb *tlvdb_find(struct tlvdb *tlvdb, tlv_tag_t tag) {
return NULL; return NULL;
} }
struct tlvdb *tlvdb_find_full(struct tlvdb *tlvdb, tlv_tag_t tag) {
if (!tlvdb)
return NULL;
for (; tlvdb; tlvdb = tlvdb->next) {
if (tlvdb->tag.tag == tag)
return tlvdb;
if (tlvdb->children) {
struct tlvdb * ch = tlvdb_find_full(tlvdb->children, tag);
if (ch)
return ch;
}
}
return NULL;
}
struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]) { struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]) {
int i = 0; int i = 0;
struct tlvdb *tnext = tlvdb; struct tlvdb *tnext = tlvdb;
@ -342,6 +360,52 @@ void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other)
tlvdb->next = other; tlvdb->next = other;
} }
void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value)
{
struct tlvdb *telm = tlvdb_find_full(tlvdb, tag);
if (telm == NULL) {
// new tlv element
tlvdb_add(tlvdb, tlvdb_fixed(tag, len, value));
} else {
// the same tlv structure
if (telm->tag.tag == tag && telm->tag.len == len && !memcmp(telm->tag.value, value, len))
return;
// replace tlv element
struct tlvdb *tnewelm = tlvdb_fixed(tag, len, value);
tnewelm->next = telm->next;
tnewelm->parent = telm->parent;
// if telm stayed first in children chain
if (telm->parent && telm->parent->children == telm) {
telm->parent->children = tnewelm;
}
// if telm have previous element
if (telm != tlvdb) {
// elm in root
struct tlvdb *celm = tlvdb;
// elm in child list of node
if (telm->parent && telm->parent->children)
celm = telm->parent->children;
// find previous element
for (; celm; celm = celm->next) {
if (celm->next == telm) {
celm->next = tnewelm;
break;
}
}
}
// free old element with childrens
telm->next = NULL;
tlvdb_free(telm);
}
return;
}
void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level) void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level)
{ {
struct tlvdb *next = NULL; struct tlvdb *next = NULL;

View file

@ -39,11 +39,13 @@ struct tlvdb *tlvdb_parse(const unsigned char *buf, size_t len);
struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len); struct tlvdb *tlvdb_parse_multi(const unsigned char *buf, size_t len);
void tlvdb_free(struct tlvdb *tlvdb); void tlvdb_free(struct tlvdb *tlvdb);
struct tlvdb *tlvdb_find_full(struct tlvdb *tlvdb, tlv_tag_t tag); // search also in childrens
struct tlvdb *tlvdb_find(struct tlvdb *tlvdb, tlv_tag_t tag); struct tlvdb *tlvdb_find(struct tlvdb *tlvdb, tlv_tag_t tag);
struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag); struct tlvdb *tlvdb_find_next(struct tlvdb *tlvdb, tlv_tag_t tag);
struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]); struct tlvdb *tlvdb_find_path(struct tlvdb *tlvdb, tlv_tag_t tag[]);
void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other); void tlvdb_add(struct tlvdb *tlvdb, struct tlvdb *other);
void tlvdb_change_or_add_node(struct tlvdb *tlvdb, tlv_tag_t tag, size_t len, const unsigned char *value);
void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level); void tlvdb_visit(const struct tlvdb *tlvdb, tlv_cb cb, void *data, int level);
const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev); const struct tlv *tlvdb_get(const struct tlvdb *tlvdb, tlv_tag_t tag, const struct tlv *prev);

63
client/jansson/Makefile Normal file
View file

@ -0,0 +1,63 @@
include_HEADERS = jansson.h
nodist_include_HEADERS = jansson_config.h
LIB_A = libjansson.a
libjansson_la_SOURCES = \
dump.c \
error.c \
hashtable.c \
hashtable.h \
hashtable_seed.c \
jansson_private.h \
load.c \
lookup3.h \
memory.c \
pack_unpack.c \
strbuffer.c \
strbuffer.h \
strconv.c \
utf.c \
utf.h \
value.c
libjansson_la_LDFLAGS = \
-no-undefined \
-export-symbols-regex '^json_' \
-version-info 15:0:11
CFILES = $(filter %.c, $(libjansson_la_SOURCES))
CMDOBJS = $(CFILES:%.c=%.o)
CLEAN = $(CMDOBJS)
CC= gcc
CFLAGS= -O2 -Wall -Wno-unused-variable -Wno-unused-function
LDFLAGS= $(SYSLDFLAGS) $(libjansson_la_LDFLAGS)
LIBS= -lm $(SYSLIBS) $(MYLIBS)
DEFAULT_INCLUDES = -I.
DEFS = -DHAVE_STDINT_H
AR= ar rcs
RANLIB= ranlib
RM= rm -f
TST= echo
SYSLDFLAGS=
SYSLIBS=
MYLIBS=
MYOBJS=
all: $(CMDOBJS)
$(AR) $(LIB_A) $(CMDOBJS)
$(RANLIB) $(LIB_A)
clean:
$(RM) $(CLEAN)
$(RM) $(LIB_A)
%.o: %.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(CFLAGS) -c -o $@ $< $(LIBS)
.PHONY: all clean

504
client/jansson/dump.c Normal file
View file

@ -0,0 +1,504 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "jansson_private.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "jansson.h"
#include "strbuffer.h"
#include "utf.h"
#define MAX_INTEGER_STR_LENGTH 100
#define MAX_REAL_STR_LENGTH 100
#define FLAGS_TO_INDENT(f) ((f) & 0x1F)
#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F)
struct buffer {
const size_t size;
size_t used;
char *data;
};
static int dump_to_strbuffer(const char *buffer, size_t size, void *data)
{
return strbuffer_append_bytes((strbuffer_t *)data, buffer, size);
}
static int dump_to_buffer(const char *buffer, size_t size, void *data)
{
struct buffer *buf = (struct buffer *)data;
if(buf->used + size <= buf->size)
memcpy(&buf->data[buf->used], buffer, size);
buf->used += size;
return 0;
}
static int dump_to_file(const char *buffer, size_t size, void *data)
{
FILE *dest = (FILE *)data;
if(fwrite(buffer, size, 1, dest) != 1)
return -1;
return 0;
}
static int dump_to_fd(const char *buffer, size_t size, void *data)
{
int *dest = (int *)data;
#ifdef HAVE_UNISTD_H
if(write(*dest, buffer, size) == (ssize_t)size)
return 0;
#endif
return -1;
}
/* 32 spaces (the maximum indentation size) */
static const char whitespace[] = " ";
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{
if(FLAGS_TO_INDENT(flags) > 0)
{
unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count;
if(dump("\n", 1, data))
return -1;
while(n_spaces > 0)
{
int cur_n = n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1;
if(dump(whitespace, cur_n, data))
return -1;
n_spaces -= cur_n;
}
}
else if(space && !(flags & JSON_COMPACT))
{
return dump(" ", 1, data);
}
return 0;
}
static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags)
{
const char *pos, *end, *lim;
int32_t codepoint;
if(dump("\"", 1, data))
return -1;
end = pos = str;
lim = str + len;
while(1)
{
const char *text;
char seq[13];
int length;
while(end < lim)
{
end = utf8_iterate(pos, lim - pos, &codepoint);
if(!end)
return -1;
/* mandatory escape or control char */
if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20)
break;
/* slash */
if((flags & JSON_ESCAPE_SLASH) && codepoint == '/')
break;
/* non-ASCII */
if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F)
break;
pos = end;
}
if(pos != str) {
if(dump(str, pos - str, data))
return -1;
}
if(end == pos)
break;
/* handle \, /, ", and control codes */
length = 2;
switch(codepoint)
{
case '\\': text = "\\\\"; break;
case '\"': text = "\\\""; break;
case '\b': text = "\\b"; break;
case '\f': text = "\\f"; break;
case '\n': text = "\\n"; break;
case '\r': text = "\\r"; break;
case '\t': text = "\\t"; break;
case '/': text = "\\/"; break;
default:
{
/* codepoint is in BMP */
if(codepoint < 0x10000)
{
snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint);
length = 6;
}
/* not in BMP -> construct a UTF-16 surrogate pair */
else
{
int32_t first, last;
codepoint -= 0x10000;
first = 0xD800 | ((codepoint & 0xffc00) >> 10);
last = 0xDC00 | (codepoint & 0x003ff);
snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, (unsigned int)last);
length = 12;
}
text = seq;
break;
}
}
if(dump(text, length, data))
return -1;
str = pos = end;
}
return dump("\"", 1, data);
}
static int compare_keys(const void *key1, const void *key2)
{
return strcmp(*(const char **)key1, *(const char **)key2);
}
static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size)
{
snprintf(key, key_size, "%p", json);
if (hashtable_get(parents, key))
return -1;
return hashtable_set(parents, key, json_null());
}
static int do_dump(const json_t *json, size_t flags, int depth,
hashtable_t *parents, json_dump_callback_t dump, void *data)
{
int embed = flags & JSON_EMBED;
flags &= ~JSON_EMBED;
if(!json)
return -1;
switch(json_typeof(json)) {
case JSON_NULL:
return dump("null", 4, data);
case JSON_TRUE:
return dump("true", 4, data);
case JSON_FALSE:
return dump("false", 5, data);
case JSON_INTEGER:
{
char buffer[MAX_INTEGER_STR_LENGTH];
int size;
size = snprintf(buffer, MAX_INTEGER_STR_LENGTH,
"%" JSON_INTEGER_FORMAT,
json_integer_value(json));
if(size < 0 || size >= MAX_INTEGER_STR_LENGTH)
return -1;
return dump(buffer, size, data);
}
case JSON_REAL:
{
char buffer[MAX_REAL_STR_LENGTH];
int size;
double value = json_real_value(json);
size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value,
FLAGS_TO_PRECISION(flags));
if(size < 0)
return -1;
return dump(buffer, size, data);
}
case JSON_STRING:
return dump_string(json_string_value(json), json_string_length(json), dump, data, flags);
case JSON_ARRAY:
{
size_t n;
size_t i;
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
char key[2 + (sizeof(json) * 2) + 1];
/* detect circular references */
if (loop_check(parents, json, key, sizeof(key)))
return -1;
n = json_array_size(json);
if(!embed && dump("[", 1, data))
return -1;
if(n == 0) {
hashtable_del(parents, key);
return embed ? 0 : dump("]", 1, data);
}
if(dump_indent(flags, depth + 1, 0, dump, data))
return -1;
for(i = 0; i < n; ++i) {
if(do_dump(json_array_get(json, i), flags, depth + 1,
parents, dump, data))
return -1;
if(i < n - 1)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
return -1;
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
return -1;
}
}
hashtable_del(parents, key);
return embed ? 0 : dump("]", 1, data);
}
case JSON_OBJECT:
{
void *iter;
const char *separator;
int separator_length;
/* Space for "0x", double the sizeof a pointer for the hex and a terminator. */
char key[2 + (sizeof(json) * 2) + 1];
if(flags & JSON_COMPACT) {
separator = ":";
separator_length = 1;
}
else {
separator = ": ";
separator_length = 2;
}
/* detect circular references */
if (loop_check(parents, json, key, sizeof(key)))
return -1;
iter = json_object_iter((json_t *)json);
if(!embed && dump("{", 1, data))
return -1;
if(!iter) {
hashtable_del(parents, key);
return embed ? 0 : dump("}", 1, data);
}
if(dump_indent(flags, depth + 1, 0, dump, data))
return -1;
if(flags & JSON_SORT_KEYS)
{
const char **keys;
size_t size, i;
size = json_object_size(json);
keys = jsonp_malloc(size * sizeof(const char *));
if(!keys)
return -1;
i = 0;
while(iter)
{
keys[i] = json_object_iter_key(iter);
iter = json_object_iter_next((json_t *)json, iter);
i++;
}
assert(i == size);
qsort(keys, size, sizeof(const char *), compare_keys);
for(i = 0; i < size; i++)
{
const char *key;
json_t *value;
key = keys[i];
value = json_object_get(json, key);
assert(value);
dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(value, flags, depth + 1, parents, dump, data))
{
jsonp_free(keys);
return -1;
}
if(i < size - 1)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
{
jsonp_free(keys);
return -1;
}
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
{
jsonp_free(keys);
return -1;
}
}
}
jsonp_free(keys);
}
else
{
/* Don't sort keys */
while(iter)
{
void *next = json_object_iter_next((json_t *)json, iter);
const char *key = json_object_iter_key(iter);
dump_string(key, strlen(key), dump, data, flags);
if(dump(separator, separator_length, data) ||
do_dump(json_object_iter_value(iter), flags, depth + 1,
parents, dump, data))
return -1;
if(next)
{
if(dump(",", 1, data) ||
dump_indent(flags, depth + 1, 1, dump, data))
return -1;
}
else
{
if(dump_indent(flags, depth, 0, dump, data))
return -1;
}
iter = next;
}
}
hashtable_del(parents, key);
return embed ? 0 : dump("}", 1, data);
}
default:
/* not reached */
return -1;
}
}
char *json_dumps(const json_t *json, size_t flags)
{
strbuffer_t strbuff;
char *result;
if(strbuffer_init(&strbuff))
return NULL;
if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags))
result = NULL;
else
result = jsonp_strdup(strbuffer_value(&strbuff));
strbuffer_close(&strbuff);
return result;
}
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags)
{
struct buffer buf = { size, 0, buffer };
if(json_dump_callback(json, dump_to_buffer, (void *)&buf, flags))
return 0;
return buf.used;
}
int json_dumpf(const json_t *json, FILE *output, size_t flags)
{
return json_dump_callback(json, dump_to_file, (void *)output, flags);
}
int json_dumpfd(const json_t *json, int output, size_t flags)
{
return json_dump_callback(json, dump_to_fd, (void *)&output, flags);
}
int json_dump_file(const json_t *json, const char *path, size_t flags)
{
int result;
FILE *output = fopen(path, "w");
if(!output)
return -1;
result = json_dumpf(json, output, flags);
if(fclose(output) != 0)
return -1;
return result;
}
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags)
{
int res;
hashtable_t parents_set;
if(!(flags & JSON_ENCODE_ANY)) {
if(!json_is_array(json) && !json_is_object(json))
return -1;
}
if (hashtable_init(&parents_set))
return -1;
res = do_dump(json, flags, 0, &parents_set, callback, data);
hashtable_close(&parents_set);
return res;
}

66
client/jansson/error.c Normal file
View file

@ -0,0 +1,66 @@
#include <string.h>
#include "jansson_private.h"
void jsonp_error_init(json_error_t *error, const char *source)
{
if(error)
{
error->text[0] = '\0';
error->line = -1;
error->column = -1;
error->position = 0;
if(source)
jsonp_error_set_source(error, source);
else
error->source[0] = '\0';
}
}
void jsonp_error_set_source(json_error_t *error, const char *source)
{
size_t length;
if(!error || !source)
return;
length = strlen(source);
if(length < JSON_ERROR_SOURCE_LENGTH)
strncpy(error->source, source, length + 1);
else {
size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4;
strncpy(error->source, "...", 3);
strncpy(error->source + 3, source + extra, length - extra + 1);
}
}
void jsonp_error_set(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
jsonp_error_vset(error, line, column, position, code, msg, ap);
va_end(ap);
}
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, va_list ap)
{
if(!error)
return;
if(error->text[0] != '\0') {
/* error already set */
return;
}
error->line = line;
error->column = column;
error->position = (int)position;
vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap);
error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0';
error->text[JSON_ERROR_TEXT_LENGTH - 1] = code;
}

356
client/jansson/hashtable.c Normal file
View file

@ -0,0 +1,356 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#if HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#include <stdlib.h>
#include <string.h>
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#include <jansson_config.h> /* for JSON_INLINE */
#include "jansson_private.h" /* for container_of() */
#include "hashtable.h"
#ifndef INITIAL_HASHTABLE_ORDER
#define INITIAL_HASHTABLE_ORDER 3
#endif
typedef struct hashtable_list list_t;
typedef struct hashtable_pair pair_t;
typedef struct hashtable_bucket bucket_t;
extern volatile uint32_t hashtable_seed;
/* Implementation of the hash function */
#include "lookup3.h"
#define list_to_pair(list_) container_of(list_, pair_t, list)
#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed))
static JSON_INLINE void list_init(list_t *list)
{
list->next = list;
list->prev = list;
}
static JSON_INLINE void list_insert(list_t *list, list_t *node)
{
node->next = list;
node->prev = list->prev;
list->prev->next = node;
list->prev = node;
}
static JSON_INLINE void list_remove(list_t *list)
{
list->prev->next = list->next;
list->next->prev = list->prev;
}
static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket)
{
return bucket->first == &hashtable->list && bucket->first == bucket->last;
}
static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket,
list_t *list)
{
if(bucket_is_empty(hashtable, bucket))
{
list_insert(&hashtable->list, list);
bucket->first = bucket->last = list;
}
else
{
list_insert(bucket->first, list);
bucket->first = list;
}
}
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
const char *key, size_t hash)
{
list_t *list;
pair_t *pair;
if(bucket_is_empty(hashtable, bucket))
return NULL;
list = bucket->first;
while(1)
{
pair = list_to_pair(list);
if(pair->hash == hash && strcmp(pair->key, key) == 0)
return pair;
if(list == bucket->last)
break;
list = list->next;
}
return NULL;
}
/* returns 0 on success, -1 if key was not found */
static int hashtable_do_del(hashtable_t *hashtable,
const char *key, size_t hash)
{
pair_t *pair;
bucket_t *bucket;
size_t index;
index = hash & hashmask(hashtable->order);
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
return -1;
if(&pair->list == bucket->first && &pair->list == bucket->last)
bucket->first = bucket->last = &hashtable->list;
else if(&pair->list == bucket->first)
bucket->first = pair->list.next;
else if(&pair->list == bucket->last)
bucket->last = pair->list.prev;
list_remove(&pair->list);
list_remove(&pair->ordered_list);
json_decref(pair->value);
jsonp_free(pair);
hashtable->size--;
return 0;
}
static void hashtable_do_clear(hashtable_t *hashtable)
{
list_t *list, *next;
pair_t *pair;
for(list = hashtable->list.next; list != &hashtable->list; list = next)
{
next = list->next;
pair = list_to_pair(list);
json_decref(pair->value);
jsonp_free(pair);
}
}
static int hashtable_do_rehash(hashtable_t *hashtable)
{
list_t *list, *next;
pair_t *pair;
size_t i, index, new_size, new_order;
struct hashtable_bucket *new_buckets;
new_order = hashtable->order + 1;
new_size = hashsize(new_order);
new_buckets = jsonp_malloc(new_size * sizeof(bucket_t));
if(!new_buckets)
return -1;
jsonp_free(hashtable->buckets);
hashtable->buckets = new_buckets;
hashtable->order = new_order;
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
}
list = hashtable->list.next;
list_init(&hashtable->list);
for(; list != &hashtable->list; list = next) {
next = list->next;
pair = list_to_pair(list);
index = pair->hash % new_size;
insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list);
}
return 0;
}
int hashtable_init(hashtable_t *hashtable)
{
size_t i;
hashtable->size = 0;
hashtable->order = INITIAL_HASHTABLE_ORDER;
hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t));
if(!hashtable->buckets)
return -1;
list_init(&hashtable->list);
list_init(&hashtable->ordered_list);
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
}
return 0;
}
void hashtable_close(hashtable_t *hashtable)
{
hashtable_do_clear(hashtable);
jsonp_free(hashtable->buckets);
}
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value)
{
pair_t *pair;
bucket_t *bucket;
size_t hash, index;
/* rehash if the load ratio exceeds 1 */
if(hashtable->size >= hashsize(hashtable->order))
if(hashtable_do_rehash(hashtable))
return -1;
hash = hash_str(key);
index = hash & hashmask(hashtable->order);
bucket = &hashtable->buckets[index];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(pair)
{
json_decref(pair->value);
pair->value = value;
}
else
{
/* offsetof(...) returns the size of pair_t without the last,
flexible member. This way, the correct amount is
allocated. */
size_t len = strlen(key);
if(len >= (size_t)-1 - offsetof(pair_t, key)) {
/* Avoid an overflow if the key is very long */
return -1;
}
pair = jsonp_malloc(offsetof(pair_t, key) + len + 1);
if(!pair)
return -1;
pair->hash = hash;
strncpy(pair->key, key, len + 1);
pair->value = value;
list_init(&pair->list);
list_init(&pair->ordered_list);
insert_to_bucket(hashtable, bucket, &pair->list);
list_insert(&hashtable->ordered_list, &pair->ordered_list);
hashtable->size++;
}
return 0;
}
void *hashtable_get(hashtable_t *hashtable, const char *key)
{
pair_t *pair;
size_t hash;
bucket_t *bucket;
hash = hash_str(key);
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
return NULL;
return pair->value;
}
int hashtable_del(hashtable_t *hashtable, const char *key)
{
size_t hash = hash_str(key);
return hashtable_do_del(hashtable, key, hash);
}
void hashtable_clear(hashtable_t *hashtable)
{
size_t i;
hashtable_do_clear(hashtable);
for(i = 0; i < hashsize(hashtable->order); i++)
{
hashtable->buckets[i].first = hashtable->buckets[i].last =
&hashtable->list;
}
list_init(&hashtable->list);
list_init(&hashtable->ordered_list);
hashtable->size = 0;
}
void *hashtable_iter(hashtable_t *hashtable)
{
return hashtable_iter_next(hashtable, &hashtable->ordered_list);
}
void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
{
pair_t *pair;
size_t hash;
bucket_t *bucket;
hash = hash_str(key);
bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
pair = hashtable_find_pair(hashtable, bucket, key, hash);
if(!pair)
return NULL;
return &pair->ordered_list;
}
void *hashtable_iter_next(hashtable_t *hashtable, void *iter)
{
list_t *list = (list_t *)iter;
if(list->next == &hashtable->ordered_list)
return NULL;
return list->next;
}
void *hashtable_iter_key(void *iter)
{
pair_t *pair = ordered_list_to_pair((list_t *)iter);
return pair->key;
}
void *hashtable_iter_value(void *iter)
{
pair_t *pair = ordered_list_to_pair((list_t *)iter);
return pair->value;
}
void hashtable_iter_set(void *iter, json_t *value)
{
pair_t *pair = ordered_list_to_pair((list_t *)iter);
json_decref(pair->value);
pair->value = value;
}

176
client/jansson/hashtable.h Normal file
View file

@ -0,0 +1,176 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <stdlib.h>
#include "jansson.h"
struct hashtable_list {
struct hashtable_list *prev;
struct hashtable_list *next;
};
/* "pair" may be a bit confusing a name, but think of it as a
key-value pair. In this case, it just encodes some extra data,
too */
struct hashtable_pair {
struct hashtable_list list;
struct hashtable_list ordered_list;
size_t hash;
json_t *value;
char key[1];
};
struct hashtable_bucket {
struct hashtable_list *first;
struct hashtable_list *last;
};
typedef struct hashtable {
size_t size;
struct hashtable_bucket *buckets;
size_t order; /* hashtable has pow(2, order) buckets */
struct hashtable_list list;
struct hashtable_list ordered_list;
} hashtable_t;
#define hashtable_key_to_iter(key_) \
(&(container_of(key_, struct hashtable_pair, key)->ordered_list))
/**
* hashtable_init - Initialize a hashtable object
*
* @hashtable: The (statically allocated) hashtable object
*
* Initializes a statically allocated hashtable object. The object
* should be cleared with hashtable_close when it's no longer used.
*
* Returns 0 on success, -1 on error (out of memory).
*/
int hashtable_init(hashtable_t *hashtable);
/**
* hashtable_close - Release all resources used by a hashtable object
*
* @hashtable: The hashtable
*
* Destroys a statically allocated hashtable object.
*/
void hashtable_close(hashtable_t *hashtable);
/**
* hashtable_set - Add/modify value in hashtable
*
* @hashtable: The hashtable object
* @key: The key
* @serial: For addition order of keys
* @value: The value
*
* If a value with the given key already exists, its value is replaced
* with the new value. Value is "stealed" in the sense that hashtable
* doesn't increment its refcount but decreases the refcount when the
* value is no longer needed.
*
* Returns 0 on success, -1 on failure (out of memory).
*/
int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value);
/**
* hashtable_get - Get a value associated with a key
*
* @hashtable: The hashtable object
* @key: The key
*
* Returns value if it is found, or NULL otherwise.
*/
void *hashtable_get(hashtable_t *hashtable, const char *key);
/**
* hashtable_del - Remove a value from the hashtable
*
* @hashtable: The hashtable object
* @key: The key
*
* Returns 0 on success, or -1 if the key was not found.
*/
int hashtable_del(hashtable_t *hashtable, const char *key);
/**
* hashtable_clear - Clear hashtable
*
* @hashtable: The hashtable object
*
* Removes all items from the hashtable.
*/
void hashtable_clear(hashtable_t *hashtable);
/**
* hashtable_iter - Iterate over hashtable
*
* @hashtable: The hashtable object
*
* Returns an opaque iterator to the first element in the hashtable.
* The iterator should be passed to hashtable_iter_* functions.
* The hashtable items are not iterated over in any particular order.
*
* There's no need to free the iterator in any way. The iterator is
* valid as long as the item that is referenced by the iterator is not
* deleted. Other values may be added or deleted. In particular,
* hashtable_iter_next() may be called on an iterator, and after that
* the key/value pair pointed by the old iterator may be deleted.
*/
void *hashtable_iter(hashtable_t *hashtable);
/**
* hashtable_iter_at - Return an iterator at a specific key
*
* @hashtable: The hashtable object
* @key: The key that the iterator should point to
*
* Like hashtable_iter() but returns an iterator pointing to a
* specific key.
*/
void *hashtable_iter_at(hashtable_t *hashtable, const char *key);
/**
* hashtable_iter_next - Advance an iterator
*
* @hashtable: The hashtable object
* @iter: The iterator
*
* Returns a new iterator pointing to the next element in the
* hashtable or NULL if the whole hastable has been iterated over.
*/
void *hashtable_iter_next(hashtable_t *hashtable, void *iter);
/**
* hashtable_iter_key - Retrieve the key pointed by an iterator
*
* @iter: The iterator
*/
void *hashtable_iter_key(void *iter);
/**
* hashtable_iter_value - Retrieve the value pointed by an iterator
*
* @iter: The iterator
*/
void *hashtable_iter_value(void *iter);
/**
* hashtable_iter_set - Set the value pointed by an iterator
*
* @iter: The iterator
* @value: The value to set
*/
void hashtable_iter_set(void *iter, json_t *value);
#endif

View file

@ -0,0 +1,277 @@
/* Generate sizeof(uint32_t) bytes of as random data as possible to seed
the hash function.
*/
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#include <stdio.h>
#include <time.h>
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_SCHED_H
#include <sched.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if defined(_WIN32)
/* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */
#include <windows.h>
#endif
#include "jansson.h"
static uint32_t buf_to_uint32(char *data) {
size_t i;
uint32_t result = 0;
for (i = 0; i < sizeof(uint32_t); i++)
result = (result << 8) | (unsigned char)data[i];
return result;
}
/* /dev/urandom */
#if !defined(_WIN32) && defined(USE_URANDOM)
static int seed_from_urandom(uint32_t *seed) {
/* Use unbuffered I/O if we have open(), close() and read(). Otherwise
fall back to fopen() */
char data[sizeof(uint32_t)];
int ok;
#if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ)
int urandom;
urandom = open("/dev/urandom", O_RDONLY);
if (urandom == -1)
return 1;
ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t);
close(urandom);
#else
FILE *urandom;
urandom = fopen("/dev/urandom", "rb");
if (!urandom)
return 1;
ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t);
fclose(urandom);
#endif
if (!ok)
return 1;
*seed = buf_to_uint32(data);
return 0;
}
#endif
/* Windows Crypto API */
#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
#include <wincrypt.h>
typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags);
typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags);
static int seed_from_windows_cryptoapi(uint32_t *seed)
{
HINSTANCE hAdvAPI32 = NULL;
CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL;
CRYPTGENRANDOM pCryptGenRandom = NULL;
CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
HCRYPTPROV hCryptProv = 0;
BYTE data[sizeof(uint32_t)];
int ok;
hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll"));
if(hAdvAPI32 == NULL)
return 1;
pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA");
if (!pCryptAcquireContext)
return 1;
pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom");
if (!pCryptGenRandom)
return 1;
pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext");
if (!pCryptReleaseContext)
return 1;
if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
return 1;
ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data);
pCryptReleaseContext(hCryptProv, 0);
if (!ok)
return 1;
*seed = buf_to_uint32((char *)data);
return 0;
}
#endif
/* gettimeofday() and getpid() */
static int seed_from_timestamp_and_pid(uint32_t *seed) {
#ifdef HAVE_GETTIMEOFDAY
/* XOR of seconds and microseconds */
struct timeval tv;
gettimeofday(&tv, NULL);
*seed = (uint32_t)tv.tv_sec ^ (uint32_t)tv.tv_usec;
#else
/* Seconds only */
*seed = (uint32_t)time(NULL);
#endif
/* XOR with PID for more randomness */
#if defined(_WIN32)
*seed ^= (uint32_t)GetCurrentProcessId();
#elif defined(HAVE_GETPID)
*seed ^= (uint32_t)getpid();
#endif
return 0;
}
static uint32_t generate_seed() {
uint32_t seed;
int done = 0;
#if !defined(_WIN32) && defined(USE_URANDOM)
if (seed_from_urandom(&seed) == 0)
done = 1;
#endif
#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
if (seed_from_windows_cryptoapi(&seed) == 0)
done = 1;
#endif
if (!done) {
/* Fall back to timestamp and PID if no better randomness is
available */
seed_from_timestamp_and_pid(&seed);
}
/* Make sure the seed is never zero */
if (seed == 0)
seed = 1;
return seed;
}
volatile uint32_t hashtable_seed = 0;
#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
static volatile char seed_initialized = 0;
void json_object_seed(size_t seed) {
uint32_t new_seed = (uint32_t)seed;
if (hashtable_seed == 0) {
if (__atomic_test_and_set(&seed_initialized, __ATOMIC_RELAXED) == 0) {
/* Do the seeding ourselves */
if (new_seed == 0)
new_seed = generate_seed();
__atomic_store_n(&hashtable_seed, new_seed, __ATOMIC_RELEASE);
} else {
/* Wait for another thread to do the seeding */
do {
#ifdef HAVE_SCHED_YIELD
sched_yield();
#endif
} while(__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0);
}
}
}
#elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
void json_object_seed(size_t seed) {
uint32_t new_seed = (uint32_t)seed;
if (hashtable_seed == 0) {
if (new_seed == 0) {
/* Explicit synchronization fences are not supported by the
__sync builtins, so every thread getting here has to
generate the seed value.
*/
new_seed = generate_seed();
}
do {
if (__sync_bool_compare_and_swap(&hashtable_seed, 0, new_seed)) {
/* We were the first to seed */
break;
} else {
/* Wait for another thread to do the seeding */
#ifdef HAVE_SCHED_YIELD
sched_yield();
#endif
}
} while(hashtable_seed == 0);
}
}
#elif defined(_WIN32)
static long seed_initialized = 0;
void json_object_seed(size_t seed) {
uint32_t new_seed = (uint32_t)seed;
if (hashtable_seed == 0) {
if (InterlockedIncrement(&seed_initialized) == 1) {
/* Do the seeding ourselves */
if (new_seed == 0)
new_seed = generate_seed();
hashtable_seed = new_seed;
} else {
/* Wait for another thread to do the seeding */
do {
SwitchToThread();
} while (hashtable_seed == 0);
}
}
}
#else
/* Fall back to a thread-unsafe version */
void json_object_seed(size_t seed) {
uint32_t new_seed = (uint32_t)seed;
if (hashtable_seed == 0) {
if (new_seed == 0)
new_seed = generate_seed();
hashtable_seed = new_seed;
}
}
#endif

View file

@ -0,0 +1,75 @@
EXPORTS
json_delete
json_true
json_false
json_null
json_sprintf
json_vsprintf
json_string
json_stringn
json_string_nocheck
json_stringn_nocheck
json_string_value
json_string_length
json_string_set
json_string_setn
json_string_set_nocheck
json_string_setn_nocheck
json_integer
json_integer_value
json_integer_set
json_real
json_real_value
json_real_set
json_number_value
json_array
json_array_size
json_array_get
json_array_set_new
json_array_append_new
json_array_insert_new
json_array_remove
json_array_clear
json_array_extend
json_object
json_object_size
json_object_get
json_object_set_new
json_object_set_new_nocheck
json_object_del
json_object_clear
json_object_update
json_object_update_existing
json_object_update_missing
json_object_iter
json_object_iter_at
json_object_iter_next
json_object_iter_key
json_object_iter_value
json_object_iter_set_new
json_object_key_to_iter
json_object_seed
json_dumps
json_dumpb
json_dumpf
json_dumpfd
json_dump_file
json_dump_callback
json_loads
json_loadb
json_loadf
json_loadfd
json_load_file
json_load_callback
json_equal
json_copy
json_deep_copy
json_pack
json_pack_ex
json_vpack_ex
json_unpack
json_unpack_ex
json_vunpack_ex
json_set_alloc_funcs
json_get_alloc_funcs

362
client/jansson/jansson.h Normal file
View file

@ -0,0 +1,362 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef JANSSON_H
#define JANSSON_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h> /* for size_t */
#include <stdarg.h>
#include "jansson_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/* version */
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 11
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.11"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \
(JANSSON_MINOR_VERSION << 8) | \
(JANSSON_MICRO_VERSION << 0))
/* If __atomic or __sync builtins are available the library is thread
* safe for all read-only functions plus reference counting. */
#if JSON_HAVE_ATOMIC_BUILTINS || JSON_HAVE_SYNC_BUILTINS
#define JANSSON_THREAD_SAFE_REFCOUNT 1
#endif
/* types */
typedef enum {
JSON_OBJECT,
JSON_ARRAY,
JSON_STRING,
JSON_INTEGER,
JSON_REAL,
JSON_TRUE,
JSON_FALSE,
JSON_NULL
} json_type;
typedef struct json_t {
json_type type;
volatile size_t refcount;
} json_t;
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
#if JSON_INTEGER_IS_LONG_LONG
#ifdef _WIN32
#define JSON_INTEGER_FORMAT "I64d"
#else
#define JSON_INTEGER_FORMAT "lld"
#endif
typedef long long json_int_t;
#else
#define JSON_INTEGER_FORMAT "ld"
typedef long json_int_t;
#endif /* JSON_INTEGER_IS_LONG_LONG */
#endif
#define json_typeof(json) ((json)->type)
#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT)
#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY)
#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING)
#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER)
#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL)
#define json_is_number(json) (json_is_integer(json) || json_is_real(json))
#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE)
#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE)
#define json_boolean_value json_is_true
#define json_is_boolean(json) (json_is_true(json) || json_is_false(json))
#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL)
/* construction, destruction, reference counting */
json_t *json_object(void);
json_t *json_array(void);
json_t *json_string(const char *value);
json_t *json_stringn(const char *value, size_t len);
json_t *json_string_nocheck(const char *value);
json_t *json_stringn_nocheck(const char *value, size_t len);
json_t *json_integer(json_int_t value);
json_t *json_real(double value);
json_t *json_true(void);
json_t *json_false(void);
#define json_boolean(val) ((val) ? json_true() : json_false())
json_t *json_null(void);
/* do not call JSON_INTERNAL_INCREF or JSON_INTERNAL_DECREF directly */
#if JSON_HAVE_ATOMIC_BUILTINS
#define JSON_INTERNAL_INCREF(json) __atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE)
#define JSON_INTERNAL_DECREF(json) __atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE)
#elif JSON_HAVE_SYNC_BUILTINS
#define JSON_INTERNAL_INCREF(json) __sync_add_and_fetch(&json->refcount, 1)
#define JSON_INTERNAL_DECREF(json) __sync_sub_and_fetch(&json->refcount, 1)
#else
#define JSON_INTERNAL_INCREF(json) (++json->refcount)
#define JSON_INTERNAL_DECREF(json) (--json->refcount)
#endif
static JSON_INLINE
json_t *json_incref(json_t *json)
{
if(json && json->refcount != (size_t)-1)
JSON_INTERNAL_INCREF(json);
return json;
}
/* do not call json_delete directly */
void json_delete(json_t *json);
static JSON_INLINE
void json_decref(json_t *json)
{
if(json && json->refcount != (size_t)-1 && JSON_INTERNAL_DECREF(json) == 0)
json_delete(json);
}
#if defined(__GNUC__) || defined(__clang__)
static JSON_INLINE
void json_decrefp(json_t **json)
{
if(json) {
json_decref(*json);
*json = NULL;
}
}
#define json_auto_t json_t __attribute__((cleanup(json_decrefp)))
#endif
/* error reporting */
#define JSON_ERROR_TEXT_LENGTH 160
#define JSON_ERROR_SOURCE_LENGTH 80
typedef struct json_error_t {
int line;
int column;
int position;
char source[JSON_ERROR_SOURCE_LENGTH];
char text[JSON_ERROR_TEXT_LENGTH];
} json_error_t;
enum json_error_code {
json_error_unknown,
json_error_out_of_memory,
json_error_stack_overflow,
json_error_cannot_open_file,
json_error_invalid_argument,
json_error_invalid_utf8,
json_error_premature_end_of_input,
json_error_end_of_input_expected,
json_error_invalid_syntax,
json_error_invalid_format,
json_error_wrong_type,
json_error_null_character,
json_error_null_value,
json_error_null_byte_in_key,
json_error_duplicate_key,
json_error_numeric_overflow,
json_error_item_not_found,
json_error_index_out_of_range
};
static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) {
return (enum json_error_code)e->text[JSON_ERROR_TEXT_LENGTH - 1];
}
/* getters, setters, manipulation */
void json_object_seed(size_t seed);
size_t json_object_size(const json_t *object);
json_t *json_object_get(const json_t *object, const char *key);
int json_object_set_new(json_t *object, const char *key, json_t *value);
int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value);
int json_object_del(json_t *object, const char *key);
int json_object_clear(json_t *object);
int json_object_update(json_t *object, json_t *other);
int json_object_update_existing(json_t *object, json_t *other);
int json_object_update_missing(json_t *object, json_t *other);
void *json_object_iter(json_t *object);
void *json_object_iter_at(json_t *object, const char *key);
void *json_object_key_to_iter(const char *key);
void *json_object_iter_next(json_t *object, void *iter);
const char *json_object_iter_key(void *iter);
json_t *json_object_iter_value(void *iter);
int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
#define json_object_foreach(object, key, value) \
for(key = json_object_iter_key(json_object_iter(object)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key))))
#define json_object_foreach_safe(object, n, key, value) \
for(key = json_object_iter_key(json_object_iter(object)), \
n = json_object_iter_next(object, json_object_key_to_iter(key)); \
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(n), \
n = json_object_iter_next(object, json_object_key_to_iter(key)))
#define json_array_foreach(array, index, value) \
for(index = 0; \
index < json_array_size(array) && (value = json_array_get(array, index)); \
index++)
static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value)
{
return json_object_set_new(object, key, json_incref(value));
}
static JSON_INLINE
int json_object_set_nocheck(json_t *object, const char *key, json_t *value)
{
return json_object_set_new_nocheck(object, key, json_incref(value));
}
static JSON_INLINE
int json_object_iter_set(json_t *object, void *iter, json_t *value)
{
return json_object_iter_set_new(object, iter, json_incref(value));
}
size_t json_array_size(const json_t *array);
json_t *json_array_get(const json_t *array, size_t index);
int json_array_set_new(json_t *array, size_t index, json_t *value);
int json_array_append_new(json_t *array, json_t *value);
int json_array_insert_new(json_t *array, size_t index, json_t *value);
int json_array_remove(json_t *array, size_t index);
int json_array_clear(json_t *array);
int json_array_extend(json_t *array, json_t *other);
static JSON_INLINE
int json_array_set(json_t *array, size_t ind, json_t *value)
{
return json_array_set_new(array, ind, json_incref(value));
}
static JSON_INLINE
int json_array_append(json_t *array, json_t *value)
{
return json_array_append_new(array, json_incref(value));
}
static JSON_INLINE
int json_array_insert(json_t *array, size_t ind, json_t *value)
{
return json_array_insert_new(array, ind, json_incref(value));
}
const char *json_string_value(const json_t *string);
size_t json_string_length(const json_t *string);
json_int_t json_integer_value(const json_t *integer);
double json_real_value(const json_t *real);
double json_number_value(const json_t *json);
int json_string_set(json_t *string, const char *value);
int json_string_setn(json_t *string, const char *value, size_t len);
int json_string_set_nocheck(json_t *string, const char *value);
int json_string_setn_nocheck(json_t *string, const char *value, size_t len);
int json_integer_set(json_t *integer, json_int_t value);
int json_real_set(json_t *real, double value);
/* pack, unpack */
json_t *json_pack(const char *fmt, ...);
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...);
json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap);
#define JSON_VALIDATE_ONLY 0x1
#define JSON_STRICT 0x2
int json_unpack(json_t *root, const char *fmt, ...);
int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...);
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap);
/* sprintf */
json_t *json_sprintf(const char *fmt, ...);
json_t *json_vsprintf(const char *fmt, va_list ap);
/* equality */
int json_equal(const json_t *value1, const json_t *value2);
/* copying */
json_t *json_copy(json_t *value);
json_t *json_deep_copy(const json_t *value);
/* decoding */
#define JSON_REJECT_DUPLICATES 0x1
#define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
#define JSON_DECODE_INT_AS_REAL 0x8
#define JSON_ALLOW_NUL 0x10
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
json_t *json_loads(const char *input, size_t flags, json_error_t *error);
json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error);
json_t *json_loadf(FILE *input, size_t flags, json_error_t *error);
json_t *json_loadfd(int input, size_t flags, json_error_t *error);
json_t *json_load_file(const char *path, size_t flags, json_error_t *error);
json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error);
/* encoding */
#define JSON_MAX_INDENT 0x1F
#define JSON_INDENT(n) ((n) & JSON_MAX_INDENT)
#define JSON_COMPACT 0x20
#define JSON_ENSURE_ASCII 0x40
#define JSON_SORT_KEYS 0x80
#define JSON_PRESERVE_ORDER 0x100
#define JSON_ENCODE_ANY 0x200
#define JSON_ESCAPE_SLASH 0x400
#define JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11)
#define JSON_EMBED 0x10000
typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data);
char *json_dumps(const json_t *json, size_t flags);
size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags);
int json_dumpf(const json_t *json, FILE *output, size_t flags);
int json_dumpfd(const json_t *json, int output, size_t flags);
int json_dump_file(const json_t *json, const char *path, size_t flags);
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags);
/* custom memory allocation */
typedef void *(*json_malloc_t)(size_t);
typedef void (*json_free_t)(void *);
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn);
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2010-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*
*
* This file specifies a part of the site-specific configuration for
* Jansson, namely those things that affect the public API in
* jansson.h.
*
* The configure script copies this file to jansson_config.h and
* replaces @var@ substitutions by values that fit your system. If you
* cannot run the configure script, you can do the value substitution
* by hand.
*/
#ifndef JANSSON_CONFIG_H
#define JANSSON_CONFIG_H
/* If your compiler supports the inline keyword in C, JSON_INLINE is
defined to `inline', otherwise empty. In C++, the inline is always
supported. */
#ifdef __cplusplus
#define JSON_INLINE inline
#else
#define JSON_INLINE inline
#endif
/* If your compiler supports the `long long` type and the strtoll()
library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG 1
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV 1
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS 1
/* If __atomic builtins are not available we try using __sync builtins
to manage reference counts of json_t. */
#define JSON_HAVE_SYNC_BUILTINS 1
/* Maximum recursion depth for parsing JSON input.
This limits the depth of e.g. array-within-array constructions. */
#define JSON_PARSER_MAX_DEPTH 2048
#endif

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2010-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*
*
* This file specifies a part of the site-specific configuration for
* Jansson, namely those things that affect the public API in
* jansson.h.
*
* The configure script copies this file to jansson_config.h and
* replaces @var@ substitutions by values that fit your system. If you
* cannot run the configure script, you can do the value substitution
* by hand.
*/
#ifndef JANSSON_CONFIG_H
#define JANSSON_CONFIG_H
/* If your compiler supports the inline keyword in C, JSON_INLINE is
defined to `inline', otherwise empty. In C++, the inline is always
supported. */
#ifdef __cplusplus
#define JSON_INLINE inline
#else
#define JSON_INLINE @json_inline@
#endif
/* If your compiler supports the `long long` type and the strtoll()
library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV @json_have_localeconv@
/* If __atomic builtins are available they will be used to manage
reference counts of json_t. */
#define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@
/* If __atomic builtins are not available we try using __sync builtins
to manage reference counts of json_t. */
#define JSON_HAVE_SYNC_BUILTINS @json_have_sync_builtins@
/* Maximum recursion depth for parsing JSON input.
This limits the depth of e.g. array-within-array constructions. */
#define JSON_PARSER_MAX_DEPTH 2048
#endif

View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef JANSSON_PRIVATE_H
#define JANSSON_PRIVATE_H
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#include <stddef.h>
#include "jansson.h"
#include "hashtable.h"
#include "strbuffer.h"
#define container_of(ptr_, type_, member_) \
((type_ *)((char *)ptr_ - offsetof(type_, member_)))
/* On some platforms, max() may already be defined */
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
/* va_copy is a C99 feature. In C89 implementations, it's sometimes
available as __va_copy. If not, memcpy() should do the trick. */
#ifndef va_copy
#ifdef __va_copy
#define va_copy __va_copy
#else
#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list))
#endif
#endif
typedef struct {
json_t json;
hashtable_t hashtable;
} json_object_t;
typedef struct {
json_t json;
size_t size;
size_t entries;
json_t **table;
} json_array_t;
typedef struct {
json_t json;
char *value;
size_t length;
} json_string_t;
typedef struct {
json_t json;
double value;
} json_real_t;
typedef struct {
json_t json;
json_int_t value;
} json_integer_t;
#define json_to_object(json_) container_of(json_, json_object_t, json)
#define json_to_array(json_) container_of(json_, json_array_t, json)
#define json_to_string(json_) container_of(json_, json_string_t, json)
#define json_to_real(json_) container_of(json_, json_real_t, json)
#define json_to_integer(json_) container_of(json_, json_integer_t, json)
/* Create a string by taking ownership of an existing buffer */
json_t *jsonp_stringn_nocheck_own(const char *value, size_t len);
/* Error message formatting */
void jsonp_error_init(json_error_t *error, const char *source);
void jsonp_error_set_source(json_error_t *error, const char *source);
void jsonp_error_set(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, ...);
void jsonp_error_vset(json_error_t *error, int line, int column,
size_t position, enum json_error_code code,
const char *msg, va_list ap);
/* Locale independent string<->double conversions */
int jsonp_strtod(strbuffer_t *strbuffer, double *out);
int jsonp_dtostr(char *buffer, size_t size, double value, int prec);
/* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);
void jsonp_free(void *ptr);
char *jsonp_strndup(const char *str, size_t length);
char *jsonp_strdup(const char *str);
char *jsonp_strndup(const char *str, size_t len);
/* Windows compatibility */
#if defined(_WIN32) || defined(WIN32)
# if defined(_MSC_VER) /* MS compiller */
# if (_MSC_VER < 1900) && !defined(snprintf) /* snprintf not defined yet & not introduced */
# define snprintf _snprintf
# endif
# if (_MSC_VER < 1500) && !defined(vsnprintf) /* vsnprintf not defined yet & not introduced */
# define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a)
# endif
# else /* Other Windows compiller, old definition */
# define snprintf _snprintf
# define vsnprintf _vsnprintf
# endif
#endif
#endif

1155
client/jansson/load.c Normal file

File diff suppressed because it is too large Load diff

381
client/jansson/lookup3.h Normal file
View file

@ -0,0 +1,381 @@
/*
-------------------------------------------------------------------------------
lookup3.c, by Bob Jenkins, May 2006, Public Domain.
These are functions for producing 32-bit hashes for hash table lookup.
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
are externally useful functions. Routines to test the hash are included
if SELF_TEST is defined. You can use this free for any purpose. It's in
the public domain. It has no warranty.
You probably want to use hashlittle(). hashlittle() and hashbig()
hash byte arrays. hashlittle() is is faster than hashbig() on
little-endian machines. Intel and AMD are little-endian machines.
On second thought, you probably want hashlittle2(), which is identical to
hashlittle() except it returns two 32-bit hashes for the price of one.
You could implement hashbig2() if you wanted but I haven't bothered here.
If you want to find a hash of, say, exactly 7 integers, do
a = i1; b = i2; c = i3;
mix(a,b,c);
a += i4; b += i5; c += i6;
mix(a,b,c);
a += i7;
final(a,b,c);
then use c as the hash value. If you have a variable length array of
4-byte integers to hash, use hashword(). If you have a byte array (like
a character string), use hashlittle(). If you have several byte arrays, or
a mix of things, see the comments above hashlittle().
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
then mix those integers. This is fast (you can do a lot more thorough
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
-------------------------------------------------------------------------------
*/
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h> /* defines uint32_t etc */
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> /* attempt to define endianness */
#endif
#ifdef HAVE_ENDIAN_H
# include <endian.h> /* attempt to define endianness */
#endif
/*
* My best guess at if you are big-endian or little-endian. This may
* need adjustment.
*/
#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
__BYTE_ORDER == __LITTLE_ENDIAN) || \
(defined(i386) || defined(__i386__) || defined(__i486__) || \
defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
# define HASH_LITTLE_ENDIAN 1
# define HASH_BIG_ENDIAN 0
#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
__BYTE_ORDER == __BIG_ENDIAN) || \
(defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
# define HASH_LITTLE_ENDIAN 0
# define HASH_BIG_ENDIAN 1
#else
# define HASH_LITTLE_ENDIAN 0
# define HASH_BIG_ENDIAN 0
#endif
#define hashsize(n) ((uint32_t)1<<(n))
#define hashmask(n) (hashsize(n)-1)
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
/*
-------------------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
This is reversible, so any information in (a,b,c) before mix() is
still in (a,b,c) after mix().
If four pairs of (a,b,c) inputs are run through mix(), or through
mix() in reverse, there are at least 32 bits of the output that
are sometimes the same for one pair and different for another pair.
This was tested for:
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
satisfy this are
4 6 8 16 19 4
9 15 3 18 27 15
14 9 3 7 17 3
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
for "differ" defined as + with a one-bit base and a two-bit delta. I
used http://burtleburtle.net/bob/hash/avalanche.html to choose
the operations, constants, and arrangements of the variables.
This does not achieve avalanche. There are input bits of (a,b,c)
that fail to affect some output bits of (a,b,c), especially of a. The
most thoroughly mixed value is c, but it doesn't really even achieve
avalanche in c.
This allows some parallelism. Read-after-writes are good at doubling
the number of bits affected, so the goal of mixing pulls in the opposite
direction as the goal of parallelism. I did what I could. Rotates
seem to cost as much as shifts on every machine I could lay my hands
on, and rotates are much kinder to the top and bottom bits, so I used
rotates.
-------------------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= c; a ^= rot(c, 4); c += b; \
b -= a; b ^= rot(a, 6); a += c; \
c -= b; c ^= rot(b, 8); b += a; \
a -= c; a ^= rot(c,16); c += b; \
b -= a; b ^= rot(a,19); a += c; \
c -= b; c ^= rot(b, 4); b += a; \
}
/*
-------------------------------------------------------------------------------
final -- final mixing of 3 32-bit values (a,b,c) into c
Pairs of (a,b,c) values differing in only a few bits will usually
produce values of c that look totally different. This was tested for
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
These constants passed:
14 11 25 16 4 14 24
12 14 25 16 4 14 24
and these came close:
4 8 15 26 3 22 24
10 8 15 26 3 22 24
11 8 15 26 3 22 24
-------------------------------------------------------------------------------
*/
#define final(a,b,c) \
{ \
c ^= b; c -= rot(b,14); \
a ^= c; a -= rot(c,11); \
b ^= a; b -= rot(a,25); \
c ^= b; c -= rot(b,16); \
a ^= c; a -= rot(c,4); \
b ^= a; b -= rot(a,14); \
c ^= b; c -= rot(b,24); \
}
/*
-------------------------------------------------------------------------------
hashlittle() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
length : the length of the key, counting by bytes
initval : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Two keys differing by one or two bits will have
totally different hash values.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (uint8_t **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial. It's free.
Use for hash table lookup, or anything where one collision in 2^^32 is
acceptable. Do NOT use for cryptographic purposes.
-------------------------------------------------------------------------------
*/
static uint32_t hashlittle(const void *key, size_t length, uint32_t initval)
{
uint32_t a,b,c; /* internal state */
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
/* Set up the internal state */
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
u.ptr = key;
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
/* Detect Valgrind or AddressSanitizer */
#ifdef VALGRIND
# define NO_MASKING_TRICK 1
#else
# if defined(__has_feature) /* Clang */
# if __has_feature(address_sanitizer) /* is ASAN enabled? */
# define NO_MASKING_TRICK 1
# endif
# else
# if defined(__SANITIZE_ADDRESS__) /* GCC 4.8.x, is ASAN enabled? */
# define NO_MASKING_TRICK 1
# endif
# endif
#endif
#ifdef NO_MASKING_TRICK
const uint8_t *k8;
#endif
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
b += k[1];
c += k[2];
mix(a,b,c);
length -= 12;
k += 3;
}
/*----------------------------- handle the last (probably partial) block */
/*
* "k[2]&0xffffff" actually reads beyond the end of the string, but
* then masks off the part it's not allowed to read. Because the
* string is aligned, the masked-off tail is in the same word as the
* rest of the string. Every machine with memory protection I've seen
* does it on word boundaries, so is OK with this. But VALGRIND will
* still catch it and complain. The masking trick does make the hash
* noticably faster for short strings (like English words).
*/
#ifndef NO_MASKING_TRICK
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
case 5 : b+=k[1]&0xff; a+=k[0]; break;
case 4 : a+=k[0]; break;
case 3 : a+=k[0]&0xffffff; break;
case 2 : a+=k[0]&0xffff; break;
case 1 : a+=k[0]&0xff; break;
case 0 : return c; /* zero length strings require no mixing */
}
#else /* make valgrind happy */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]; break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
case 1 : a+=k8[0]; break;
case 0 : return c;
}
#endif /* !valgrind */
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
const uint8_t *k8;
/*--------------- all but last block: aligned reads and different mixing */
while (length > 12)
{
a += k[0] + (((uint32_t)k[1])<<16);
b += k[2] + (((uint32_t)k[3])<<16);
c += k[4] + (((uint32_t)k[5])<<16);
mix(a,b,c);
length -= 12;
k += 6;
}
/*----------------------------- handle the last (probably partial) block */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=k[4];
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=k[2];
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=k[0];
break;
case 1 : a+=k8[0];
break;
case 0 : return c; /* zero length requires no mixing */
}
} else { /* need to read the key one byte at a time */
const uint8_t *k = (const uint8_t *)key;
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
a += ((uint32_t)k[1])<<8;
a += ((uint32_t)k[2])<<16;
a += ((uint32_t)k[3])<<24;
b += k[4];
b += ((uint32_t)k[5])<<8;
b += ((uint32_t)k[6])<<16;
b += ((uint32_t)k[7])<<24;
c += k[8];
c += ((uint32_t)k[9])<<8;
c += ((uint32_t)k[10])<<16;
c += ((uint32_t)k[11])<<24;
mix(a,b,c);
length -= 12;
k += 12;
}
/*-------------------------------- last block: affect all 32 bits of (c) */
switch(length) /* all the case statements fall through */
{
case 12: c+=((uint32_t)k[11])<<24; /* fall through */
case 11: c+=((uint32_t)k[10])<<16; /* fall through */
case 10: c+=((uint32_t)k[9])<<8; /* fall through */
case 9 : c+=k[8]; /* fall through */
case 8 : b+=((uint32_t)k[7])<<24; /* fall through */
case 7 : b+=((uint32_t)k[6])<<16; /* fall through */
case 6 : b+=((uint32_t)k[5])<<8; /* fall through */
case 5 : b+=k[4]; /* fall through */
case 4 : a+=((uint32_t)k[3])<<24; /* fall through */
case 3 : a+=((uint32_t)k[2])<<16; /* fall through */
case 2 : a+=((uint32_t)k[1])<<8; /* fall through */
case 1 : a+=k[0];
break;
case 0 : return c;
}
}
final(a,b,c);
return c;
}

69
client/jansson/memory.c Normal file
View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
*
* Jansson is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See LICENSE for details.
*/
#include <stdlib.h>
#include <string.h>
#include "jansson.h"
#include "jansson_private.h"
/* C89 allows these to be macros */
#undef malloc
#undef free
/* memory function pointers */
static json_malloc_t do_malloc = malloc;
static json_free_t do_free = free;
void *jsonp_malloc(size_t size)
{
if(!size)
return NULL;
return (*do_malloc)(size);
}
void jsonp_free(void *ptr)
{
if(!ptr)
return;
(*do_free)(ptr);
}
char *jsonp_strdup(const char *str)
{
return jsonp_strndup(str, strlen(str));
}
char *jsonp_strndup(const char *str, size_t len)
{
char *new_str;
new_str = jsonp_malloc(len + 1);
if(!new_str)
return NULL;
memcpy(new_str, str, len);
new_str[len] = '\0';
return new_str;
}
void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn)
{
do_malloc = malloc_fn;
do_free = free_fn;
}
void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn)
{
if (malloc_fn)
*malloc_fn = do_malloc;
if (free_fn)
*free_fn = do_free;
}

View file

@ -0,0 +1,909 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include "jansson.h"
#include "jansson_private.h"
#include "utf.h"
typedef struct {
int line;
int column;
size_t pos;
char token;
} token_t;
typedef struct {
const char *start;
const char *fmt;
token_t prev_token;
token_t token;
token_t next_token;
json_error_t *error;
size_t flags;
int line;
int column;
size_t pos;
int has_error;
} scanner_t;
#define token(scanner) ((scanner)->token.token)
static const char * const type_names[] = {
"object",
"array",
"string",
"integer",
"real",
"true",
"false",
"null"
};
#define type_name(x) type_names[json_typeof(x)]
static const char unpack_value_starters[] = "{[siIbfFOon";
static void scanner_init(scanner_t *s, json_error_t *error,
size_t flags, const char *fmt)
{
s->error = error;
s->flags = flags;
s->fmt = s->start = fmt;
memset(&s->prev_token, 0, sizeof(token_t));
memset(&s->token, 0, sizeof(token_t));
memset(&s->next_token, 0, sizeof(token_t));
s->line = 1;
s->column = 0;
s->pos = 0;
s->has_error = 0;
}
static void next_token(scanner_t *s)
{
const char *t;
s->prev_token = s->token;
if(s->next_token.line) {
s->token = s->next_token;
s->next_token.line = 0;
return;
}
t = s->fmt;
s->column++;
s->pos++;
/* skip space and ignored chars */
while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
if(*t == '\n') {
s->line++;
s->column = 1;
}
else
s->column++;
s->pos++;
t++;
}
s->token.token = *t;
s->token.line = s->line;
s->token.column = s->column;
s->token.pos = s->pos;
t++;
s->fmt = t;
}
static void prev_token(scanner_t *s)
{
s->next_token = s->token;
s->token = s->prev_token;
}
static void set_error(scanner_t *s, const char *source, enum json_error_code code,
const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos,
code, fmt, ap);
jsonp_error_set_source(s->error, source);
va_end(ap);
}
static json_t *pack(scanner_t *s, va_list *ap);
/* ours will be set to 1 if jsonp_free() must be called for the result
afterwards */
static char *read_string(scanner_t *s, va_list *ap,
const char *purpose, size_t *out_len, int *ours)
{
char t;
strbuffer_t strbuff;
const char *str;
size_t length;
next_token(s);
t = token(s);
prev_token(s);
*ours = 0;
if(t != '#' && t != '%' && t != '+') {
/* Optimize the simple case */
str = va_arg(*ap, const char *);
if(!str) {
set_error(s, "<args>", json_error_null_value, "NULL string argument");
return NULL;
}
length = strlen(str);
if(!utf8_check_string(str, length)) {
set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
return NULL;
}
*out_len = length;
return (char *)str;
}
strbuffer_init(&strbuff);
while(1) {
str = va_arg(*ap, const char *);
if(!str) {
set_error(s, "<args>", json_error_null_value, "NULL string argument");
s->has_error = 1;
}
next_token(s);
if(token(s) == '#') {
length = va_arg(*ap, int);
}
else if(token(s) == '%') {
length = va_arg(*ap, size_t);
}
else {
prev_token(s);
length = s->has_error ? 0 : strlen(str);
}
if(!s->has_error && strbuffer_append_bytes(&strbuff, str, length) == -1) {
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
s->has_error = 1;
}
next_token(s);
if(token(s) != '+') {
prev_token(s);
break;
}
}
if(s->has_error) {
strbuffer_close(&strbuff);
return NULL;
}
if(!utf8_check_string(strbuff.value, strbuff.length)) {
set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose);
strbuffer_close(&strbuff);
s->has_error = 1;
return NULL;
}
*out_len = strbuff.length;
*ours = 1;
return strbuffer_steal_value(&strbuff);
}
static json_t *pack_object(scanner_t *s, va_list *ap)
{
json_t *object = json_object();
next_token(s);
while(token(s) != '}') {
char *key;
size_t len;
int ours;
json_t *value;
if(!token(s)) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
goto error;
}
if(token(s) != 's') {
set_error(s, "<format>", json_error_invalid_format, "Expected format 's', got '%c'", token(s));
goto error;
}
key = read_string(s, ap, "object key", &len, &ours);
if (!key)
s->has_error = 1;
next_token(s);
value = pack(s, ap);
if(!value) {
if(ours)
jsonp_free(key);
if(strchr("soO", token(s)) && s->next_token.token == '*') {
next_token(s);
} else {
s->has_error = 1;
}
next_token(s);
continue;
}
if(s->has_error)
json_decref(value);
if(!s->has_error && json_object_set_new_nocheck(object, key, value)) {
set_error(s, "<internal>", json_error_out_of_memory, "Unable to add key \"%s\"", key);
s->has_error = 1;
}
if(ours)
jsonp_free(key);
if(strchr("soO", token(s)) && s->next_token.token == '*')
next_token(s);
next_token(s);
}
if(!s->has_error)
return object;
error:
json_decref(object);
return NULL;
}
static json_t *pack_array(scanner_t *s, va_list *ap)
{
json_t *array = json_array();
next_token(s);
while(token(s) != ']') {
json_t *value;
if(!token(s)) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
/* Format string errors are unrecoverable. */
goto error;
}
value = pack(s, ap);
if(!value) {
if(strchr("soO", token(s)) && s->next_token.token == '*') {
next_token(s);
} else {
s->has_error = 1;
}
next_token(s);
continue;
}
if(s->has_error)
json_decref(value);
if(!s->has_error && json_array_append_new(array, value)) {
set_error(s, "<internal>", json_error_out_of_memory, "Unable to append to array");
s->has_error = 1;
}
if(strchr("soO", token(s)) && s->next_token.token == '*')
next_token(s);
next_token(s);
}
if(!s->has_error)
return array;
error:
json_decref(array);
return NULL;
}
static json_t *pack_string(scanner_t *s, va_list *ap)
{
char *str;
size_t len;
int ours;
int nullable;
next_token(s);
nullable = token(s) == '?';
if (!nullable)
prev_token(s);
str = read_string(s, ap, "string", &len, &ours);
if (!str) {
return nullable ? json_null() : NULL;
} else if (ours) {
return jsonp_stringn_nocheck_own(str, len);
} else {
return json_stringn_nocheck(str, len);
}
}
static json_t *pack(scanner_t *s, va_list *ap)
{
switch(token(s)) {
case '{':
return pack_object(s, ap);
case '[':
return pack_array(s, ap);
case 's': /* string */
return pack_string(s, ap);
case 'n': /* null */
return json_null();
case 'b': /* boolean */
return va_arg(*ap, int) ? json_true() : json_false();
case 'i': /* integer from int */
return json_integer(va_arg(*ap, int));
case 'I': /* integer from json_int_t */
return json_integer(va_arg(*ap, json_int_t));
case 'f': /* real */
return json_real(va_arg(*ap, double));
case 'O': /* a json_t object; increments refcount */
{
int nullable;
json_t *json;
next_token(s);
nullable = token(s) == '?';
if (!nullable)
prev_token(s);
json = va_arg(*ap, json_t *);
if (!json && nullable) {
return json_null();
} else {
return json_incref(json);
}
}
case 'o': /* a json_t object; doesn't increment refcount */
{
int nullable;
json_t *json;
next_token(s);
nullable = token(s) == '?';
if (!nullable)
prev_token(s);
json = va_arg(*ap, json_t *);
if (!json && nullable) {
return json_null();
} else {
return json;
}
}
default:
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
token(s));
s->has_error = 1;
return NULL;
}
}
static int unpack(scanner_t *s, json_t *root, va_list *ap);
static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
{
int ret = -1;
int strict = 0;
int gotopt = 0;
/* Use a set (emulated by a hashtable) to check that all object
keys are accessed. Checking that the correct number of keys
were accessed is not enough, as the same key can be unpacked
multiple times.
*/
hashtable_t key_set;
if(hashtable_init(&key_set)) {
set_error(s, "<internal>", json_error_out_of_memory, "Out of memory");
return -1;
}
if(root && !json_is_object(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected object, got %s",
type_name(root));
goto out;
}
next_token(s);
while(token(s) != '}') {
const char *key;
json_t *value;
int opt = 0;
if(strict != 0) {
set_error(s, "<format>", json_error_invalid_format, "Expected '}' after '%c', got '%c'",
(strict == 1 ? '!' : '*'), token(s));
goto out;
}
if(!token(s)) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
goto out;
}
if(token(s) == '!' || token(s) == '*') {
strict = (token(s) == '!' ? 1 : -1);
next_token(s);
continue;
}
if(token(s) != 's') {
set_error(s, "<format>", json_error_invalid_format, "Expected format 's', got '%c'", token(s));
goto out;
}
key = va_arg(*ap, const char *);
if(!key) {
set_error(s, "<args>", json_error_null_value, "NULL object key");
goto out;
}
next_token(s);
if(token(s) == '?') {
opt = gotopt = 1;
next_token(s);
}
if(!root) {
/* skipping */
value = NULL;
}
else {
value = json_object_get(root, key);
if(!value && !opt) {
set_error(s, "<validation>", json_error_item_not_found, "Object item not found: %s", key);
goto out;
}
}
if(unpack(s, value, ap))
goto out;
hashtable_set(&key_set, key, json_null());
next_token(s);
}
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(root && strict == 1) {
/* We need to check that all non optional items have been parsed */
const char *key;
int have_unrecognized_keys = 0;
strbuffer_t unrecognized_keys;
json_t *value;
long unpacked = 0;
if (gotopt) {
/* We have optional keys, we need to iter on each key */
json_object_foreach(root, key, value) {
if(!hashtable_get(&key_set, key)) {
unpacked++;
/* Save unrecognized keys for the error message */
if (!have_unrecognized_keys) {
strbuffer_init(&unrecognized_keys);
have_unrecognized_keys = 1;
} else {
strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
}
strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
}
}
} else {
/* No optional keys, we can just compare the number of items */
unpacked = (long)json_object_size(root) - (long)key_set.size;
}
if (unpacked) {
if (!gotopt) {
/* Save unrecognized keys for the error message */
json_object_foreach(root, key, value) {
if(!hashtable_get(&key_set, key)) {
if (!have_unrecognized_keys) {
strbuffer_init(&unrecognized_keys);
have_unrecognized_keys = 1;
} else {
strbuffer_append_bytes(&unrecognized_keys, ", ", 2);
}
strbuffer_append_bytes(&unrecognized_keys, key, strlen(key));
}
}
}
set_error(s, "<validation>", json_error_end_of_input_expected,
"%li object item(s) left unpacked: %s",
unpacked, strbuffer_value(&unrecognized_keys));
strbuffer_close(&unrecognized_keys);
goto out;
}
}
ret = 0;
out:
hashtable_close(&key_set);
return ret;
}
static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
{
size_t i = 0;
int strict = 0;
if(root && !json_is_array(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected array, got %s", type_name(root));
return -1;
}
next_token(s);
while(token(s) != ']') {
json_t *value;
if(strict != 0) {
set_error(s, "<format>", json_error_invalid_format, "Expected ']' after '%c', got '%c'",
(strict == 1 ? '!' : '*'),
token(s));
return -1;
}
if(!token(s)) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string");
return -1;
}
if(token(s) == '!' || token(s) == '*') {
strict = (token(s) == '!' ? 1 : -1);
next_token(s);
continue;
}
if(!strchr(unpack_value_starters, token(s))) {
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
token(s));
return -1;
}
if(!root) {
/* skipping */
value = NULL;
}
else {
value = json_array_get(root, i);
if(!value) {
set_error(s, "<validation>", json_error_index_out_of_range, "Array index %lu out of range",
(unsigned long)i);
return -1;
}
}
if(unpack(s, value, ap))
return -1;
next_token(s);
i++;
}
if(strict == 0 && (s->flags & JSON_STRICT))
strict = 1;
if(root && strict == 1 && i != json_array_size(root)) {
long diff = (long)json_array_size(root) - (long)i;
set_error(s, "<validation>", json_error_end_of_input_expected, "%li array item(s) left unpacked", diff);
return -1;
}
return 0;
}
static int unpack(scanner_t *s, json_t *root, va_list *ap)
{
switch(token(s))
{
case '{':
return unpack_object(s, root, ap);
case '[':
return unpack_array(s, root, ap);
case 's':
if(root && !json_is_string(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected string, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
const char **str_target;
size_t *len_target = NULL;
str_target = va_arg(*ap, const char **);
if(!str_target) {
set_error(s, "<args>", json_error_null_value, "NULL string argument");
return -1;
}
next_token(s);
if(token(s) == '%') {
len_target = va_arg(*ap, size_t *);
if(!len_target) {
set_error(s, "<args>", json_error_null_value, "NULL string length argument");
return -1;
}
}
else
prev_token(s);
if(root) {
*str_target = json_string_value(root);
if(len_target)
*len_target = json_string_length(root);
}
}
return 0;
case 'i':
if(root && !json_is_integer(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
int *target = va_arg(*ap, int*);
if(root)
*target = (int)json_integer_value(root);
}
return 0;
case 'I':
if(root && !json_is_integer(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
json_int_t *target = va_arg(*ap, json_int_t*);
if(root)
*target = json_integer_value(root);
}
return 0;
case 'b':
if(root && !json_is_boolean(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected true or false, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
int *target = va_arg(*ap, int*);
if(root)
*target = json_is_true(root);
}
return 0;
case 'f':
if(root && !json_is_real(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected real, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
double *target = va_arg(*ap, double*);
if(root)
*target = json_real_value(root);
}
return 0;
case 'F':
if(root && !json_is_number(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected real or integer, got %s",
type_name(root));
return -1;
}
if(!(s->flags & JSON_VALIDATE_ONLY)) {
double *target = va_arg(*ap, double*);
if(root)
*target = json_number_value(root);
}
return 0;
case 'O':
if(root && !(s->flags & JSON_VALIDATE_ONLY))
json_incref(root);
/* Fall through */
case 'o':
if(!(s->flags & JSON_VALIDATE_ONLY)) {
json_t **target = va_arg(*ap, json_t**);
if(root)
*target = root;
}
return 0;
case 'n':
/* Never assign, just validate */
if(root && !json_is_null(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected null, got %s",
type_name(root));
return -1;
}
return 0;
default:
set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'",
token(s));
return -1;
}
}
json_t *json_vpack_ex(json_error_t *error, size_t flags,
const char *fmt, va_list ap)
{
scanner_t s;
va_list ap_copy;
json_t *value;
if(!fmt || !*fmt) {
jsonp_error_init(error, "<format>");
jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "NULL or empty format string");
return NULL;
}
jsonp_error_init(error, NULL);
scanner_init(&s, error, flags, fmt);
next_token(&s);
va_copy(ap_copy, ap);
value = pack(&s, &ap_copy);
va_end(ap_copy);
if(!value)
return NULL;
next_token(&s);
if(token(&s)) {
json_decref(value);
set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string");
return NULL;
}
if(s.has_error) {
json_decref(value);
return NULL;
}
return value;
}
json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...)
{
json_t *value;
va_list ap;
va_start(ap, fmt);
value = json_vpack_ex(error, flags, fmt, ap);
va_end(ap);
return value;
}
json_t *json_pack(const char *fmt, ...)
{
json_t *value;
va_list ap;
va_start(ap, fmt);
value = json_vpack_ex(NULL, 0, fmt, ap);
va_end(ap);
return value;
}
int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
const char *fmt, va_list ap)
{
scanner_t s;
va_list ap_copy;
if(!root) {
jsonp_error_init(error, "<root>");
jsonp_error_set(error, -1, -1, 0, json_error_null_value, "NULL root value");
return -1;
}
if(!fmt || !*fmt) {
jsonp_error_init(error, "<format>");
jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "NULL or empty format string");
return -1;
}
jsonp_error_init(error, NULL);
scanner_init(&s, error, flags, fmt);
next_token(&s);
va_copy(ap_copy, ap);
if(unpack(&s, root, &ap_copy)) {
va_end(ap_copy);
return -1;
}
va_end(ap_copy);
next_token(&s);
if(token(&s)) {
set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string");
return -1;
}
return 0;
}
int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = json_vunpack_ex(root, error, flags, fmt, ap);
va_end(ap);
return ret;
}
int json_unpack(json_t *root, const char *fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = json_vunpack_ex(root, NULL, 0, fmt, ap);
va_end(ap);
return ret;
}

111
client/jansson/strbuffer.c Normal file
View file

@ -0,0 +1,111 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <string.h>
#include "jansson_private.h"
#include "strbuffer.h"
#define STRBUFFER_MIN_SIZE 16
#define STRBUFFER_FACTOR 2
#define STRBUFFER_SIZE_MAX ((size_t)-1)
int strbuffer_init(strbuffer_t *strbuff)
{
strbuff->size = STRBUFFER_MIN_SIZE;
strbuff->length = 0;
strbuff->value = jsonp_malloc(strbuff->size);
if(!strbuff->value)
return -1;
/* initialize to empty */
strbuff->value[0] = '\0';
return 0;
}
void strbuffer_close(strbuffer_t *strbuff)
{
if(strbuff->value)
jsonp_free(strbuff->value);
strbuff->size = 0;
strbuff->length = 0;
strbuff->value = NULL;
}
void strbuffer_clear(strbuffer_t *strbuff)
{
strbuff->length = 0;
strbuff->value[0] = '\0';
}
const char *strbuffer_value(const strbuffer_t *strbuff)
{
return strbuff->value;
}
char *strbuffer_steal_value(strbuffer_t *strbuff)
{
char *result = strbuff->value;
strbuff->value = NULL;
return result;
}
int strbuffer_append_byte(strbuffer_t *strbuff, char byte)
{
return strbuffer_append_bytes(strbuff, &byte, 1);
}
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size)
{
if(size >= strbuff->size - strbuff->length)
{
size_t new_size;
char *new_value;
/* avoid integer overflow */
if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR
|| size > STRBUFFER_SIZE_MAX - 1
|| strbuff->length > STRBUFFER_SIZE_MAX - 1 - size)
return -1;
new_size = max(strbuff->size * STRBUFFER_FACTOR,
strbuff->length + size + 1);
new_value = jsonp_malloc(new_size);
if(!new_value)
return -1;
memcpy(new_value, strbuff->value, strbuff->length);
jsonp_free(strbuff->value);
strbuff->value = new_value;
strbuff->size = new_size;
}
memcpy(strbuff->value + strbuff->length, data, size);
strbuff->length += size;
strbuff->value[strbuff->length] = '\0';
return 0;
}
char strbuffer_pop(strbuffer_t *strbuff)
{
if(strbuff->length > 0) {
char c = strbuff->value[--strbuff->length];
strbuff->value[strbuff->length] = '\0';
return c;
}
else
return '\0';
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef STRBUFFER_H
#define STRBUFFER_H
#include <stdlib.h>
typedef struct {
char *value;
size_t length; /* bytes used */
size_t size; /* bytes allocated */
} strbuffer_t;
int strbuffer_init(strbuffer_t *strbuff);
void strbuffer_close(strbuffer_t *strbuff);
void strbuffer_clear(strbuffer_t *strbuff);
const char *strbuffer_value(const strbuffer_t *strbuff);
/* Steal the value and close the strbuffer */
char *strbuffer_steal_value(strbuffer_t *strbuff);
int strbuffer_append_byte(strbuffer_t *strbuff, char byte);
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size);
char strbuffer_pop(strbuffer_t *strbuff);
#endif

145
client/jansson/strconv.c Normal file
View file

@ -0,0 +1,145 @@
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef __MINGW32__
#undef __NO_ISOCEXT /* ensure stdlib.h will declare prototypes for mingw own 'strtod' replacement, called '__strtod' */
#endif
#include "jansson_private.h"
#include "strbuffer.h"
/* need jansson_private_config.h to get the correct snprintf */
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#ifdef __MINGW32__
#define strtod __strtod
#endif
#if JSON_HAVE_LOCALECONV
#include <locale.h>
/*
- This code assumes that the decimal separator is exactly one
character.
- If setlocale() is called by another thread between the call to
localeconv() and the call to sprintf() or strtod(), the result may
be wrong. setlocale() is not thread-safe and should not be used
this way. Multi-threaded programs should use uselocale() instead.
*/
static void to_locale(strbuffer_t *strbuffer)
{
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(strbuffer->value, '.');
if(pos)
*pos = *point;
}
static void from_locale(char *buffer)
{
const char *point;
char *pos;
point = localeconv()->decimal_point;
if(*point == '.') {
/* No conversion needed */
return;
}
pos = strchr(buffer, *point);
if(pos)
*pos = '.';
}
#endif
int jsonp_strtod(strbuffer_t *strbuffer, double *out)
{
double value;
char *end;
#if JSON_HAVE_LOCALECONV
to_locale(strbuffer);
#endif
errno = 0;
value = strtod(strbuffer->value, &end);
assert(end == strbuffer->value + strbuffer->length);
if((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) {
/* Overflow */
return -1;
}
*out = value;
return 0;
}
int jsonp_dtostr(char *buffer, size_t size, double value, int precision)
{
int ret;
char *start, *end;
size_t length;
if (precision == 0)
precision = 17;
ret = snprintf(buffer, size, "%.*g", precision, value);
if(ret < 0)
return -1;
length = (size_t)ret;
if(length >= size)
return -1;
#if JSON_HAVE_LOCALECONV
from_locale(buffer);
#endif
/* Make sure there's a dot or 'e' in the output. Otherwise
a real is converted to an integer when decoding */
if(strchr(buffer, '.') == NULL &&
strchr(buffer, 'e') == NULL)
{
if(length + 3 >= size) {
/* No space to append ".0" */
return -1;
}
buffer[length] = '.';
buffer[length + 1] = '0';
buffer[length + 2] = '\0';
length += 2;
}
/* Remove leading '+' from positive exponent. Also remove leading
zeros from exponents (added by some printf() implementations) */
start = strchr(buffer, 'e');
if(start) {
start++;
end = start + 1;
if(*start == '-')
start++;
while(*end == '0')
end++;
if(end != start) {
memmove(start, end, length - (size_t)(end - buffer));
length -= (size_t)(end - start);
}
}
return (int)length;
}

187
client/jansson/utf.c Normal file
View file

@ -0,0 +1,187 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <string.h>
#include "utf.h"
int utf8_encode(int32_t codepoint, char *buffer, size_t *size)
{
if(codepoint < 0)
return -1;
else if(codepoint < 0x80)
{
buffer[0] = (char)codepoint;
*size = 1;
}
else if(codepoint < 0x800)
{
buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6);
buffer[1] = 0x80 + ((codepoint & 0x03F));
*size = 2;
}
else if(codepoint < 0x10000)
{
buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12);
buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6);
buffer[2] = 0x80 + ((codepoint & 0x003F));
*size = 3;
}
else if(codepoint <= 0x10FFFF)
{
buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18);
buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12);
buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6);
buffer[3] = 0x80 + ((codepoint & 0x00003F));
*size = 4;
}
else
return -1;
return 0;
}
size_t utf8_check_first(char byte)
{
unsigned char u = (unsigned char)byte;
if(u < 0x80)
return 1;
if(0x80 <= u && u <= 0xBF) {
/* second, third or fourth byte of a multi-byte
sequence, i.e. a "continuation byte" */
return 0;
}
else if(u == 0xC0 || u == 0xC1) {
/* overlong encoding of an ASCII byte */
return 0;
}
else if(0xC2 <= u && u <= 0xDF) {
/* 2-byte sequence */
return 2;
}
else if(0xE0 <= u && u <= 0xEF) {
/* 3-byte sequence */
return 3;
}
else if(0xF0 <= u && u <= 0xF4) {
/* 4-byte sequence */
return 4;
}
else { /* u >= 0xF5 */
/* Restricted (start of 4-, 5- or 6-byte sequence) or invalid
UTF-8 */
return 0;
}
}
size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint)
{
size_t i;
int32_t value = 0;
unsigned char u = (unsigned char)buffer[0];
if(size == 2)
{
value = u & 0x1F;
}
else if(size == 3)
{
value = u & 0xF;
}
else if(size == 4)
{
value = u & 0x7;
}
else
return 0;
for(i = 1; i < size; i++)
{
u = (unsigned char)buffer[i];
if(u < 0x80 || u > 0xBF) {
/* not a continuation byte */
return 0;
}
value = (value << 6) + (u & 0x3F);
}
if(value > 0x10FFFF) {
/* not in Unicode range */
return 0;
}
else if(0xD800 <= value && value <= 0xDFFF) {
/* invalid code point (UTF-16 surrogate halves) */
return 0;
}
else if((size == 2 && value < 0x80) ||
(size == 3 && value < 0x800) ||
(size == 4 && value < 0x10000)) {
/* overlong encoding */
return 0;
}
if(codepoint)
*codepoint = value;
return 1;
}
const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint)
{
size_t count;
int32_t value;
if(!bufsize)
return buffer;
count = utf8_check_first(buffer[0]);
if(count <= 0)
return NULL;
if(count == 1)
value = (unsigned char)buffer[0];
else
{
if(count > bufsize || !utf8_check_full(buffer, count, &value))
return NULL;
}
if(codepoint)
*codepoint = value;
return buffer + count;
}
int utf8_check_string(const char *string, size_t length)
{
size_t i;
for(i = 0; i < length; i++)
{
size_t count = utf8_check_first(string[i]);
if(count == 0)
return 0;
else if(count > 1)
{
if(count > length - i)
return 0;
if(!utf8_check_full(&string[i], count, NULL))
return 0;
i += count - 1;
}
}
return 1;
}

27
client/jansson/utf.h Normal file
View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef UTF_H
#define UTF_H
#ifdef HAVE_CONFIG_H
#include <jansson_private_config.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
int utf8_encode(int32_t codepoint, char *buffer, size_t *size);
size_t utf8_check_first(char byte);
size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint);
const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint);
int utf8_check_string(const char *string, size_t length);
#endif

1078
client/jansson/value.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -138,33 +138,6 @@ void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex
// printing and converting functions // printing and converting functions
void print_hex(const uint8_t * data, const size_t len)
{
size_t i;
for (i=0; i < len; i++)
printf("%02x ", data[i]);
printf("\n");
}
void print_hex_break(const uint8_t *data, const size_t len, uint8_t breaks) {
int rownum = 0;
printf("[%02d] | ", rownum);
for (int i = 0; i < len; ++i) {
printf("%02X ", data[i]);
// check if a line break is needed
if ( breaks > 0 && !((i+1) % breaks) && (i+1 < len) ) {
++rownum;
printf("\n[%02d] | ", rownum);
}
}
printf("\n");
}
char *sprint_hex(const uint8_t *data, const size_t len) { char *sprint_hex(const uint8_t *data, const size_t len) {
static char buf[1025] = {0}; static char buf[1025] = {0};
@ -220,27 +193,6 @@ char *sprint_bin(const uint8_t *data, const size_t len) {
return sprint_bin_break(data, len, 0); return sprint_bin_break(data, len, 0);
} }
char *sprint_hex_ascii(const uint8_t *data, const size_t len) {
static char buf[1024];
char *tmp = buf;
memset(buf, 0x00, 1024);
size_t max_len = (len > 255) ? 255 : len;
// max 255 bytes * 3 + 2 characters = 767 in buffer
sprintf(tmp, "%.765s| ", sprint_hex(data, max_len) );
size_t i = 0;
size_t pos = (max_len * 3)+2;
// add another 255 characters ascii = 1020 characters of buffer used
while(i < max_len) {
char c = data[i];
if ( (c < 32) || (c == 127))
c = '.';
sprintf(tmp+pos+i, "%c", c);
++i;
}
return buf;
}
char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len) { char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len) {
static char buf[1024]; static char buf[1024];
char *tmp = buf; char *tmp = buf;
@ -260,10 +212,6 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st
return buf; return buf;
} }
char *sprint_ascii(const uint8_t *data, const size_t len) {
return sprint_ascii_ex(data, len, 0);
}
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest) void num_to_bytes(uint64_t n, size_t len, uint8_t* dest)
{ {
while (len--) { while (len--) {
@ -324,16 +272,6 @@ uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockS
return tmp; return tmp;
} }
// takes a uint8_t src array, for len items and reverses the byte order in blocksizes (8,16,32,64),
// returns: the dest array contains the reordered src array.
void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest){
for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){
for (size_t i = 0; i < blockSize; i++){
dest[i+(blockSize*block)] = src[(blockSize-1-i)+(blockSize*block)];
}
}
}
//assumes little endian //assumes little endian
char * printBits(size_t const size, void const * const ptr) char * printBits(size_t const size, void const * const ptr)
{ {
@ -648,17 +586,6 @@ int hextobinarray(char *target, char *source)
return count; return count;
} }
// convert hex to human readable binary string
int hextobinstring(char *target, char *source)
{
int length;
if(!(length= hextobinarray(target, source)))
return 0;
binarraytobinstring(target, target, length);
return length;
}
// convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source) // convert binary array of 0x00/0x01 values to hex (safe to do in place as target will always be shorter than source)
// return number of bits converted // return number of bits converted
int binarraytohex(char *target,char *source, int length) int binarraytohex(char *target,char *source, int length)
@ -681,16 +608,6 @@ int binarraytohex(char *target,char *source, int length)
return length; return length;
} }
// convert binary array to human readable binary
void binarraytobinstring(char *target, char *source, int length)
{
int i;
for(i= 0 ; i < length ; ++i)
*(target++)= *(source++) + '0';
*target= '\0';
}
// return parity bit required to match type // return parity bit required to match type
uint8_t GetParity( uint8_t *bits, uint8_t type, int length) uint8_t GetParity( uint8_t *bits, uint8_t type, int length)
{ {
@ -718,13 +635,6 @@ void xor(unsigned char *dst, unsigned char *src, size_t len) {
*dst ^= *src; *dst ^= *src;
} }
int32_t le24toh (uint8_t data[3]) {
return (data[2] << 16) | (data[1] << 8) | data[0];
}
uint32_t le32toh (uint8_t *data) {
return (uint32_t)( (data[3]<<24) | (data[2]<<16) | (data[1]<<8) | data[0]);
}
// RotateLeft - Ultralight, Desfire, works on byte level // RotateLeft - Ultralight, Desfire, works on byte level
// 00-01-02 >> 01-02-00 // 00-01-02 >> 01-02-00
void rol(uint8_t *data, const size_t len){ void rol(uint8_t *data, const size_t len){

View file

@ -46,14 +46,11 @@ extern void FillFileNameByUID(char *fileName, uint8_t * uid, char *ext, int byte
extern void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len, extern void hex_to_buffer(const uint8_t *buf, const uint8_t *hex_data, const size_t hex_len,
const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase); const size_t hex_max_len, const size_t min_str_len, const size_t spaces_between, bool uppercase);
extern void print_hex(const uint8_t * data, const size_t len);
extern char *sprint_hex(const uint8_t * data, const size_t len); extern char *sprint_hex(const uint8_t * data, const size_t len);
extern char *sprint_hex_inrow(const uint8_t *data, const size_t len); extern char *sprint_hex_inrow(const uint8_t *data, const size_t len);
extern char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len); extern char *sprint_hex_inrow_ex(const uint8_t *data, const size_t len, const size_t min_str_len);
extern char *sprint_bin(const uint8_t * data, const size_t len); extern char *sprint_bin(const uint8_t * data, const size_t len);
extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks); extern char *sprint_bin_break(const uint8_t *data, const size_t len, const uint8_t breaks);
extern char *sprint_hex_ascii(const uint8_t *data, const size_t len);
extern char *sprint_ascii(const uint8_t *data, const size_t len);
extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len); extern char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_str_len);
extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); extern void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
@ -64,7 +61,6 @@ extern char *printBits(size_t const size, void const * const ptr);
extern char * printBitsPar(const uint8_t *b, size_t len); extern char * printBitsPar(const uint8_t *b, size_t len);
extern uint32_t SwapBits(uint32_t value, int nrbits); extern uint32_t SwapBits(uint32_t value, int nrbits);
extern uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); extern uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize);
extern void SwapEndian64ex(const uint8_t *src, const size_t len, const uint8_t blockSize, uint8_t *dest);
extern int param_getlength(const char *line, int paramnum); extern int param_getlength(const char *line, int paramnum);
extern char param_getchar(const char *line, int paramnum); extern char param_getchar(const char *line, int paramnum);
@ -82,15 +78,11 @@ extern int param_gethex_to_eol(const char *line, int paramnum, uint8_t * data, i
extern int param_getstr(const char *line, int paramnum, char * str, size_t buffersize); extern int param_getstr(const char *line, int paramnum, char * str, size_t buffersize);
extern int hextobinarray( char *target, char *source); extern int hextobinarray( char *target, char *source);
extern int hextobinstring( char *target, char *source);
extern int binarraytohex( char *target, char *source, int length); extern int binarraytohex( char *target, char *source, int length);
extern void binarraytobinstring(char *target, char *source, int length);
extern uint8_t GetParity( uint8_t *string, uint8_t type, int length); extern uint8_t GetParity( uint8_t *string, uint8_t type, int length);
extern void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length); extern void wiegand_add_parity(uint8_t *target, uint8_t *source, uint8_t length);
extern void xor(unsigned char *dst, unsigned char *src, size_t len); extern void xor(unsigned char *dst, unsigned char *src, size_t len);
extern int32_t le24toh(uint8_t data[3]);
extern uint32_t le32toh (uint8_t *data);
extern void rol(uint8_t *data, const size_t len); extern void rol(uint8_t *data, const size_t len);
extern void clean_ascii(unsigned char *buf, size_t len); extern void clean_ascii(unsigned char *buf, size_t len);

Binary file not shown.

View file

@ -197,9 +197,9 @@ begin
end end
end end
// set ssp_frame signal for corr_i_cnt = 0..3 and corr_i_cnt = 32..35 // set ssp_frame signal for corr_i_cnt = 0..3
// (send two frames with 8 Bits each) // (send one frame with 16 Bits)
if(corr_i_cnt[5:2] == 4'b0000 || corr_i_cnt[5:2] == 4'b1000) if(corr_i_cnt[5:2] == 4'b0000)
ssp_frame = 1'b1; ssp_frame = 1'b1;
else else
ssp_frame = 1'b0; ssp_frame = 1'b0;

View file

@ -42,11 +42,11 @@ begin
pwr_hi <= ck_1356megb; pwr_hi <= ck_1356megb;
pwr_oe1 <= 1'b0; pwr_oe1 <= 1'b0;
pwr_oe3 <= 1'b0; pwr_oe3 <= 1'b0;
pwr_oe4 <= ~ssp_dout; pwr_oe4 <= ssp_dout;
end end
else else
begin begin
pwr_hi <= ck_1356megb & ssp_dout; pwr_hi <= ck_1356megb & ~ssp_dout;
pwr_oe1 <= 1'b0; pwr_oe1 <= 1'b0;
pwr_oe3 <= 1'b0; pwr_oe3 <= 1'b0;
pwr_oe4 <= 1'b0; pwr_oe4 <= 1'b0;