From f5524ddf379c928faaf1de93b7b55d83d0958c8b Mon Sep 17 00:00:00 2001 From: Damien Zammit Date: Fri, 21 Jun 2019 21:51:43 +1000 Subject: ptformat: Update lib from legacy parser to new parser 6240b87 --- libs/ptformat/MSVCptformat/ptformat.vcproj | 4 +- libs/ptformat/ptfformat.cc | 2512 ---------------------------- libs/ptformat/ptformat.cc | 1350 +++++++++++++++ libs/ptformat/ptformat/ptfformat.h | 195 --- libs/ptformat/ptformat/ptformat.h | 282 ++++ libs/ptformat/wscript | 4 +- 6 files changed, 1636 insertions(+), 2711 deletions(-) delete mode 100644 libs/ptformat/ptfformat.cc create mode 100644 libs/ptformat/ptformat.cc delete mode 100644 libs/ptformat/ptformat/ptfformat.h create mode 100644 libs/ptformat/ptformat/ptformat.h diff --git a/libs/ptformat/MSVCptformat/ptformat.vcproj b/libs/ptformat/MSVCptformat/ptformat.vcproj index f8b440ba61..65e20a1eba 100644 --- a/libs/ptformat/MSVCptformat/ptformat.vcproj +++ b/libs/ptformat/MSVCptformat/ptformat.vcproj @@ -262,7 +262,7 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > @@ -272,7 +272,7 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > -#include -#include -#include -#include - -#include - -#include "ptformat/ptfformat.h" - -#if 0 -#define verbose_printf(...) printf(__VA_ARGS__) -#else -#define verbose_printf(...) -#endif - -using namespace std; - -static bool wavidx_compare(PTFFormat::wav_t& w1, PTFFormat::wav_t& w2) { - return w1.index < w2.index; -} - -static bool wavname_compare(PTFFormat::wav_t& w1, PTFFormat::wav_t& w2) { - return (strcasecmp(w1.filename.c_str(), w2.filename.c_str()) < 0); -} - -static bool regidx_compare(PTFFormat::region_t& r1, PTFFormat::region_t& r2) { - return r1.index < r2.index; -} - -static bool regname_compare(PTFFormat::region_t& r1, PTFFormat::region_t& r2) { - return (strcasecmp(r1.name.c_str(), r2.name.c_str()) < 0); -} - -static void -hexdump(uint8_t *data, int len) -{ - int i,j,end,step=16; - - for (i = 0; i < len; i += step) { - printf("0x%02X: ", i); - end = i + step; - if (end > len) end = len; - for (j = i; j < end; j++) { - printf("0x%02X ", data[j]); - } - for (j = i; j < end; j++) { - if (data[j] < 128 && data[j] > 32) - printf("%c", data[j]); - else - printf("."); - } - printf("\n"); - } -} - -PTFFormat::PTFFormat() : version(0), product(NULL), ptfunxored(NULL) { -} - -PTFFormat::~PTFFormat() { - cleanup(); -} - -uint16_t -PTFFormat::u_endian_read2(unsigned char *buf, bool bigendian) -{ - if (bigendian) { - return ((uint16_t)(buf[0]) << 8) | (uint16_t)(buf[1]); - } else { - return ((uint16_t)(buf[1]) << 8) | (uint16_t)(buf[0]); - } -} - -uint32_t -PTFFormat::u_endian_read3(unsigned char *buf, bool bigendian) -{ - if (bigendian) { - return ((uint32_t)(buf[0]) << 16) | - ((uint32_t)(buf[1]) << 8) | - (uint32_t)(buf[2]); - } else { - return ((uint32_t)(buf[2]) << 16) | - ((uint32_t)(buf[1]) << 8) | - (uint32_t)(buf[0]); - } -} - -uint32_t -PTFFormat::u_endian_read4(unsigned char *buf, bool bigendian) -{ - if (bigendian) { - return ((uint32_t)(buf[0]) << 24) | - ((uint32_t)(buf[1]) << 16) | - ((uint32_t)(buf[2]) << 8) | - (uint32_t)(buf[3]); - } else { - return ((uint32_t)(buf[3]) << 24) | - ((uint32_t)(buf[2]) << 16) | - ((uint32_t)(buf[1]) << 8) | - (uint32_t)(buf[0]); - } -} - -uint64_t -PTFFormat::u_endian_read5(unsigned char *buf, bool bigendian) -{ - if (bigendian) { - return ((uint64_t)(buf[0]) << 32) | - ((uint64_t)(buf[1]) << 24) | - ((uint64_t)(buf[2]) << 16) | - ((uint64_t)(buf[3]) << 8) | - (uint64_t)(buf[4]); - } else { - return ((uint64_t)(buf[4]) << 32) | - ((uint64_t)(buf[3]) << 24) | - ((uint64_t)(buf[2]) << 16) | - ((uint64_t)(buf[1]) << 8) | - (uint64_t)(buf[0]); - } -} - -void -PTFFormat::cleanup(void) { - if (ptfunxored) { - free(ptfunxored); - ptfunxored = NULL; - } - audiofiles.clear(); - regions.clear(); - midiregions.clear(); - compounds.clear(); - tracks.clear(); - miditracks.clear(); - version = 0; - product = NULL; -} - -int64_t -PTFFormat::foundat(unsigned char *haystack, uint64_t n, const char *needle) { - int64_t found = 0; - uint64_t i, j, needle_n; - needle_n = strlen(needle); - - for (i = 0; i < n; i++) { - found = i; - for (j = 0; j < needle_n; j++) { - if (haystack[i+j] != needle[j]) { - found = -1; - break; - } - } - if (found > 0) - return found; - } - return -1; -} - -bool -PTFFormat::jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) { - uint64_t i; - uint64_t k = *currpos; - while (k + needlelen < maxoffset) { - bool foundall = true; - for (i = 0; i < needlelen; i++) { - if (buf[k+i] != needle[i]) { - foundall = false; - break; - } - } - if (foundall) { - *currpos = k; - return true; - } - k++; - } - return false; -} - -bool -PTFFormat::jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) { - uint64_t i; - uint64_t k = *currpos; - while (k > 0 && k + needlelen < maxoffset) { - bool foundall = true; - for (i = 0; i < needlelen; i++) { - if (buf[k+i] != needle[i]) { - foundall = false; - break; - } - } - if (foundall) { - *currpos = k; - return true; - } - k--; - } - return false; -} - -bool -PTFFormat::foundin(std::string haystack, std::string needle) { - size_t found = haystack.find(needle); - if (found != std::string::npos) { - return true; - } else { - return false; - } -} - -/* Return values: 0 success - -1 could not decrypt pt session -*/ -int -PTFFormat::unxor(std::string path) { - FILE *fp; - unsigned char xxor[256]; - unsigned char ct; - uint64_t i; - uint8_t xor_type; - uint8_t xor_value; - uint8_t xor_delta; - uint16_t xor_len; - - if (! (fp = g_fopen(path.c_str(), "rb"))) { - return -1; - } - - fseek(fp, 0, SEEK_END); - len = ftell(fp); - if (len < 0x14) { - fclose(fp); - return -1; - } - - if (! (ptfunxored = (unsigned char*) malloc(len * sizeof(unsigned char)))) { - /* Silently fail -- out of memory*/ - fclose(fp); - ptfunxored = 0; - return -1; - } - - /* The first 20 bytes are always unencrypted */ - fseek(fp, 0x00, SEEK_SET); - i = fread(ptfunxored, 1, 0x14, fp); - if (i < 0x14) { - fclose(fp); - return -1; - } - - xor_type = ptfunxored[0x12]; - xor_value = ptfunxored[0x13]; - xor_len = 256; - - // xor_type 0x01 = ProTools 5, 6, 7, 8 and 9 - // xor_type 0x05 = ProTools 10, 11, 12 - switch(xor_type) { - case 0x01: - xor_delta = gen_xor_delta(xor_value, 53, false); - break; - case 0x05: - xor_delta = gen_xor_delta(xor_value, 11, true); - break; - default: - fclose(fp); - return -1; - } - - /* Generate the xor_key */ - for (i=0; i < xor_len; i++) - xxor[i] = (i * xor_delta) & 0xff; - - /* hexdump(xxor, xor_len); */ - - /* Read file and decrypt rest of file */ - i = 0x14; - fseek(fp, i, SEEK_SET); - while (fread(&ct, 1, 1, fp) != 0) { - uint8_t xor_index = (xor_type == 0x01) ? i & 0xff : (i >> 12) & 0xff; - ptfunxored[i++] = ct ^ xxor[xor_index]; - } - fclose(fp); - return 0; -} - -/* Return values: 0 success - -1 could not parse pt session -*/ -int -PTFFormat::load(std::string ptf, int64_t targetsr) { - cleanup(); - path = ptf; - - if (unxor(path)) - return -1; - - if (parse_version()) - return -1; - - if (version < 5 || version > 12) - return -1; - - targetrate = targetsr; - - if (parse()) - return -1; - - return 0; -} - -bool -PTFFormat::parse_version() { - uint32_t seg_len,str_len; - uint8_t *data = ptfunxored + 0x14; - uintptr_t data_end = ((uintptr_t)ptfunxored) + 0x100; - uint8_t seg_type; - bool success = false; - - while( ((uintptr_t)data < data_end) && (success == false) ) { - - if (data[0] != 0x5a) { - success = false; - break; - } - - seg_type = data[1]; - /* Skip segment header */ - data += 3; - if (data[0] == 0 && data[1] == 0) { - /* BE */ - is_bigendian = true; - } else { - /* LE */ - is_bigendian = false; - } - seg_len = u_endian_read4(&data[0], is_bigendian); - - /* Skip seg_len */ - data += 4; - if (!(seg_type == 0x04 || seg_type == 0x03) || data[0] != 0x03) { - /* Go to next segment */ - data += seg_len; - continue; - } - /* Skip 0x03 0x00 0x00 */ - data += 3; - seg_len -= 3; - str_len = (*(uint8_t *)data); - if (! (product = (uint8_t *)malloc((str_len+1) * sizeof(uint8_t)))) { - success = false; - break; - } - - /* Skip str_len */ - data += 4; - seg_len -= 4; - - memcpy(product, data, str_len); - product[str_len] = 0; - data += str_len; - seg_len -= str_len; - - /* Skip 0x03 0x00 0x00 0x00 */ - data += 4; - seg_len -= 4; - - version = data[0]; - if (version == 0) { - version = data[3]; - } - data += seg_len; - success = true; - } - - /* If the above does not work, try other heuristics */ - if ((uintptr_t)data >= data_end - seg_len) { - version = ptfunxored[0x40]; - if (version == 0) { - version = ptfunxored[0x3d]; - } - if (version == 0) { - version = ptfunxored[0x3a] + 2; - } - if (version != 0) { - success = true; - } - } - return (!success); -} - -uint8_t -PTFFormat::gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative) { - uint16_t i; - for (i = 0; i < 256; i++) { - if (((i * mul) & 0xff) == xor_value) { - return (negative) ? i * (-1) : i; - } - } - // Should not occur - return 0; -} - -int -PTFFormat::parse(void) { - if (version == 5) { - parse5header(); - setrates(); - if (sessionrate < 44100 || sessionrate > 192000) - return -1; - parseaudio5(); - parserest5(); - parsemidi(); - } else if (version == 7) { - parse7header(); - setrates(); - if (sessionrate < 44100 || sessionrate > 192000) - return -1; - parseaudio(); - parserest89(); - parsemidi(); - } else if (version == 8) { - parse8header(); - setrates(); - if (sessionrate < 44100 || sessionrate > 192000) - return -1; - parseaudio(); - parserest89(); - parsemidi(); - } else if (version == 9) { - parse9header(); - setrates(); - if (sessionrate < 44100 || sessionrate > 192000) - return -1; - parseaudio(); - parserest89(); - parsemidi(); - } else if (version == 10 || version == 11 || version == 12) { - parse10header(); - setrates(); - if (sessionrate < 44100 || sessionrate > 192000) - return -1; - parseaudio(); - parserest12(); - parsemidi12(); - } else { - // Should not occur - return -1; - } - return 0; -} - -void -PTFFormat::setrates(void) { - ratefactor = 1.f; - if (sessionrate != 0) { - ratefactor = (float)targetrate / sessionrate; - } -} - -void -PTFFormat::parse5header(void) { - uint32_t k; - - // Find session sample rate - k = 0x100; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x00\x02", 3)) { - jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2); - k--; - } - - sessionrate = u_endian_read3(&ptfunxored[k+12], is_bigendian); -} - -void -PTFFormat::parse7header(void) { - uint32_t k; - - // Find session sample rate - k = 0x100; - - jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x00\x05", 3); - - sessionrate = u_endian_read3(&ptfunxored[k+12], is_bigendian); -} - -void -PTFFormat::parse8header(void) { - uint32_t k; - - // Find session sample rate - k = 0; - - jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x05", 2); - - sessionrate = u_endian_read3(&ptfunxored[k+11], is_bigendian); -} - -void -PTFFormat::parse9header(void) { - uint32_t k; - - // Find session sample rate - k = 0x100; - - jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x06", 2); - - sessionrate = u_endian_read3(&ptfunxored[k+11], is_bigendian); -} - -void -PTFFormat::parse10header(void) { - uint32_t k; - - // Find session sample rate - k = 0x100; - - jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x09", 2); - - sessionrate = u_endian_read3(&ptfunxored[k+11], is_bigendian); -} - -void -PTFFormat::parserest5(void) { - uint32_t i, j, k; - uint64_t regionspertrack, lengthofname, numberofregions; - uint64_t startbytes, lengthbytes, offsetbytes, somethingbytes, skipbytes; - uint16_t tracknumber = 0; - uint16_t findex; - uint16_t rindex; - unsigned char tag1[3]; - unsigned char tag2[3]; - unsigned char tag3[3]; - - if (is_bigendian) { - tag1[0] = tag2[0] = tag3[0] = '\x5a'; - tag1[1] = tag2[1] = tag3[1] = '\x00'; - tag1[2] = '\x01'; - tag2[2] = '\x02'; - tag3[2] = '\x03'; - } else { - tag1[0] = tag2[0] = tag3[0] = '\x5a'; - tag1[1] = '\x01'; - tag2[1] = '\x02'; - tag3[1] = '\x03'; - tag1[2] = tag2[2] = tag3[2] = '\x00'; - } - - // Find Source->Region info - k = upto; - for (i = 0; i < 2; i++) { - jumpto(&k, ptfunxored, len, tag3, 3); - k++; - } - jumpto(&k, ptfunxored, len, tag2, 3); - - numberofregions = u_endian_read4(&ptfunxored[k-13], is_bigendian); - - i = k; - while (numberofregions > 0 && i < len) { - jumpto(&i, ptfunxored, len, tag2, 3); - - uint32_t lengthofname = u_endian_read4(&ptfunxored[i+9], is_bigendian); - - char name[256] = {0}; - for (j = 0; j < lengthofname; j++) { - name[j] = ptfunxored[i+13+j]; - } - name[j] = '\0'; - j += i+13; - //uint8_t disabled = ptfunxored[j]; - - if (is_bigendian) { - offsetbytes = (ptfunxored[j+4] & 0xf0) >> 4; - lengthbytes = (ptfunxored[j+3] & 0xf0) >> 4; - startbytes = (ptfunxored[j+2] & 0xf0) >> 4; - somethingbytes = (ptfunxored[j+2] & 0xf); - skipbytes = ptfunxored[j+1]; - } else { - offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4; //3 - lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4; - startbytes = (ptfunxored[j+3] & 0xf0) >> 4; //1 - somethingbytes = (ptfunxored[j+3] & 0xf); - skipbytes = ptfunxored[j+4]; - } - findex = u_endian_read4(&ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes], is_bigendian); - - uint32_t sampleoffset = 0; - switch (offsetbytes) { - case 4: - sampleoffset = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - sampleoffset = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - sampleoffset = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - sampleoffset = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=offsetbytes; - uint32_t length = 0; - switch (lengthbytes) { - case 4: - length = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - length = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - length = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - length = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=lengthbytes; - uint32_t start = 0; - switch (startbytes) { - case 4: - start = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - start = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - start = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - start = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=startbytes; - - std::string filename = string(name); - wav_t f = { - "", - (uint16_t)findex, - (int64_t)(start*ratefactor), - (int64_t)(length*ratefactor), - }; - - vector::iterator begin = actualwavs.begin(); - vector::iterator finish = actualwavs.end(); - vector::iterator found; - if ((found = std::find(begin, finish, f)) != finish) { - f.filename = (*found).filename; - } - std::vector m; - region_t r = { - name, - rindex, - (int64_t)(start*ratefactor), - (int64_t)(sampleoffset*ratefactor), - (int64_t)(length*ratefactor), - f, - m - }; - regions.push_back(r); - rindex++; - i = j + 1; - numberofregions--; - } - - // Find Region->Track info - /* - k = 0; - for (i = 0; i < 4; i++) { - jumpto(&k, ptfunxored, len, tag3, 3); - k++; - } - */ - k = j = i; - while (j < len) { - if (jumpto(&j, ptfunxored, j+13+3, tag1, 3)) { - j++; - if (jumpto(&j, ptfunxored, j+13+3, tag1, 3)) { - j++; - if (jumpto(&j, ptfunxored, j+13+3, tag1, 3)) { - if ((j == k+26) && (ptfunxored[j-13] == '\x5a') && (ptfunxored[j-26] == '\x5a')) { - k = j; - break; - } - } - } - } - k++; - j = k; - } - - if (ptfunxored[k+13] == '\x5a') { - k++; - } - - // Start parsing track info - rindex = 0; - while (k < len) { - if ( (ptfunxored[k ] == 0xff) && - (ptfunxored[k+1] == 0xff)) { - break; - } - jumpto(&k, ptfunxored, len, tag1, 3); - - lengthofname = u_endian_read4(&ptfunxored[k+9], is_bigendian); - if (ptfunxored[k+13] == 0x5a) { - k++; - break; - } - char name[256] = {0}; - for (j = 0; j < lengthofname; j++) { - name[j] = ptfunxored[k+13+j]; - } - name[j] = '\0'; - regionspertrack = u_endian_read4(&ptfunxored[k+13+j], is_bigendian); - for (i = 0; i < regionspertrack; i++) { - jumpto(&k, ptfunxored, len, tag3, 3); - j = k + 15; - if (is_bigendian) { - offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4; - //somethingbytes = (ptfunxored[j+2] & 0xf); - lengthbytes = (ptfunxored[j+3] & 0xf0) >> 4; - startbytes = (ptfunxored[j+4] & 0xf0) >> 4; - } else { - offsetbytes = (ptfunxored[j+4] & 0xf0) >> 4; - //somethingbytes = (ptfunxored[j+3] & 0xf); - lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4; - startbytes = (ptfunxored[j+1] & 0xf0) >> 4; - } - rindex = u_endian_read4(&ptfunxored[k+11], is_bigendian); - uint32_t start = 0; - switch (startbytes) { - case 4: - start = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - start = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - start = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - start = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=startbytes; - uint32_t length = 0; - switch (lengthbytes) { - case 4: - length = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - length = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - length = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - length = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=lengthbytes; - uint32_t sampleoffset = 0; - switch (offsetbytes) { - case 4: - sampleoffset = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - sampleoffset = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - sampleoffset = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - sampleoffset = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=offsetbytes; - - track_t tr; - tr.name = name; - - region_t r; - r.index = rindex; - - vector::iterator begin = regions.begin(); - vector::iterator finish = regions.end(); - vector::iterator found; - if ((found = std::find(begin, finish, r)) != finish) { - tr.reg = (*found); - } - - tr.reg.startpos = (int64_t)(start*ratefactor); - tr.reg.sampleoffset = (int64_t)(sampleoffset*ratefactor); - tr.reg.length = (int64_t)(length*ratefactor); - vector::iterator ti; - vector::iterator bt = tracks.begin(); - vector::iterator et = tracks.end(); - if ((ti = std::find(bt, et, tr)) != et) { - tracknumber = (*ti).index; - } else { - ++tracknumber; - } - track_t t = { - name, - (uint16_t)tracknumber, - uint8_t(0), - tr.reg - }; - //if (tr.reg.length > 0) { - tracks.push_back(t); - //} - k++; - } - k++; - } -} - -void -PTFFormat::resort(std::vector& ws) { - int j = 0; - std::sort(ws.begin(), ws.end()); - for (std::vector::iterator i = ws.begin(); i != ws.end(); ++i) { - (*i).index = j; - j++; - } -} - -void -PTFFormat::resort(std::vector& rs) { - int j = 0; - //std::sort(rs.begin(), rs.end()); - for (std::vector::iterator i = rs.begin(); i != rs.end(); ++i) { - (*i).index = j; - j++; - } -} - -void -PTFFormat::filter(std::vector& rs) { - for (std::vector::iterator i = rs.begin(); i != rs.end(); ++i) { - if (i->length == 0) - rs.erase(i); - } -} - -void -PTFFormat::parseaudio5(void) { - uint32_t i,k,l; - uint64_t lengthofname, wavnumber; - uint32_t numberofwavs; - unsigned char tag6_LE[3], tag5_BE[3]; - unsigned char tag2_LE[3], tag2_BE[3]; - - // Find start of wav file list - k = 0; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4)) - return; - numberofwavs = u_endian_read4(&ptfunxored[k-18], is_bigendian); - - // Find actual wav names - char wavname[256]; - i = k; - jumpto(&i, ptfunxored, len, (const unsigned char *)"Files", 5); - - wavnumber = 0; - i+=16; - char ext[5]; - while (i < len && numberofwavs > 0) { - i++; - if ( ((ptfunxored[i ] == 0x5a) && - (ptfunxored[i+1] == 0x00) && - (ptfunxored[i+2] == 0x05)) || - ((ptfunxored[i ] == 0x5a) && - (ptfunxored[i+1] == 0x06))) { - break; - } - lengthofname = u_endian_read4(&ptfunxored[i-3], is_bigendian); - i++; - l = 0; - while (l < lengthofname) { - wavname[l] = ptfunxored[i+l]; - l++; - } - i+=lengthofname; - ext[0] = ptfunxored[i++]; - ext[1] = ptfunxored[i++]; - ext[2] = ptfunxored[i++]; - ext[3] = ptfunxored[i++]; - ext[4] = '\0'; - - wavname[l] = 0; - if (foundin(wavname, ".L") || foundin(wavname, ".R")) { - extension = string(""); - } else if (foundin(wavname, ".wav") || foundin(ext, "WAVE")) { - extension = string(".wav"); - } else if (foundin(wavname, ".aif") || foundin(ext, "AIFF")) { - extension = string(".aif"); - } else { - extension = string(""); - } - - std::string wave = string(wavname); - - if (foundin(wave, string(".grp"))) { - continue; - } - if (foundin(wave, string("Fade Files"))) { - i += 7; - continue; - } - - wav_t f = { wave, (uint16_t)(wavnumber++), 0, 0 }; - - actualwavs.push_back(f); - audiofiles.push_back(f); - //printf("done\n"); - numberofwavs--; - i += 7; - } - - i -= 7; - - tag5_BE[0] = tag6_LE[0] = tag2_BE[0] = tag2_LE[0] = '\x5a'; - tag5_BE[1] = '\x00'; - tag6_LE[1] = '\x06'; - tag2_BE[1] = '\x00'; - tag2_LE[1] = '\x02'; - tag5_BE[2] = '\x05'; - tag6_LE[2] = '\x00'; - tag2_BE[2] = '\x02'; - tag2_LE[2] = '\x00'; - - // Loop through all the sources - for (vector::iterator w = audiofiles.begin(); w != audiofiles.end(); ++w) { - // Jump to start of source metadata for this source - if (is_bigendian) { - if (!jumpto(&i, ptfunxored, len, tag5_BE, 3)) - return; - if (!jumpto(&i, ptfunxored, len, tag2_BE, 3)) - return; - w->length = u_endian_read4(&ptfunxored[i+19], true); - } else { - if (!jumpto(&i, ptfunxored, len, tag6_LE, 3)) - return; - if (!jumpto(&i, ptfunxored, len, tag2_LE, 3)) - return; - w->length = u_endian_read4(&ptfunxored[i+15], false); - } - } - upto = i; -} - -struct mchunk { - mchunk (uint64_t zt, uint64_t ml, std::vector const& c) - : zero (zt) - , maxlen (ml) - , chunk (c) - {} - uint64_t zero; - uint64_t maxlen; - std::vector chunk; -}; - -void -PTFFormat::parsemidi(void) { - uint32_t i, k; - uint64_t tr, n_midi_events, zero_ticks; - uint64_t midi_pos, midi_len, max_pos, region_pos; - uint8_t midi_velocity, midi_note; - uint16_t ridx; - uint16_t nmiditracks, regionnumber = 0; - uint32_t nregions, mr; - - std::vector midichunks; - midi_ev_t m; - - // Find MdNLB - k = 0; - - // Parse all midi chunks, not 1:1 mapping to regions yet - while (k + 35 < len) { - max_pos = 0; - std::vector midi; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"MdNLB", 5)) { - break; - } - k += 11; - n_midi_events = ptfunxored[k] | ptfunxored[k+1] << 8 | - ptfunxored[k+2] << 16 | ptfunxored[k+3] << 24; - - k += 4; - zero_ticks = u_endian_read5(&ptfunxored[k], is_bigendian); - for (i = 0; i < n_midi_events && k < len; i++, k += 35) { - midi_pos = u_endian_read5(&ptfunxored[k], is_bigendian); - midi_pos -= zero_ticks; - midi_note = ptfunxored[k+8]; - midi_len = u_endian_read5(&ptfunxored[k+9], is_bigendian); - midi_velocity = ptfunxored[k+17]; - - if (midi_pos + midi_len > max_pos) { - max_pos = midi_pos + midi_len; - } - - m.pos = midi_pos; - m.length = midi_len; - m.note = midi_note; - m.velocity = midi_velocity; -#if 1 -// stop gap measure to prevent crashes in ardour, -// remove when decryption is fully solved for .ptx - if ((m.velocity & 0x80) || (m.note & 0x80) || - (m.pos & 0xff00000000LL) || (m.length & 0xff00000000LL)) { - continue; - } -#endif - midi.push_back(m); - } - midichunks.push_back(mchunk (zero_ticks, max_pos, midi)); - } - - // Map midi chunks to regions - while (k < len) { - char midiregionname[256]; - uint8_t namelen; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"MdTEL", 5)) { - break; - } - - k += 41; - - nregions = u_endian_read2(&ptfunxored[k], is_bigendian); - - for (mr = 0; mr < nregions; mr++) { - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x0c", 2)) { - break; - } - - k += 9; - - namelen = ptfunxored[k]; - for (i = 0; i < namelen; i++) { - midiregionname[i] = ptfunxored[k+4+i]; - } - midiregionname[namelen] = '\0'; - k += 4 + namelen; - - k += 5; - /* - region_pos = (uint64_t)ptfunxored[k] | - (uint64_t)ptfunxored[k+1] << 8 | - (uint64_t)ptfunxored[k+2] << 16 | - (uint64_t)ptfunxored[k+3] << 24 | - (uint64_t)ptfunxored[k+4] << 32; - */ - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xfe\xff\xff\xff", 4)) { - break; - } - - k += 40; - - ridx = ptfunxored[k]; - ridx |= ptfunxored[k+1] << 8; - - struct mchunk mc = *(midichunks.begin()+ridx); - - wav_t w = { std::string(""), 0, 0, 0 }; - region_t r = { - midiregionname, - regionnumber++, - //(int64_t)mc.zero, - (int64_t)0xe8d4a51000ULL, - (int64_t)(0), - //(int64_t)(max_pos*sessionrate*60/(960000*120)), - (int64_t)mc.maxlen, - w, - mc.chunk, - }; - midiregions.push_back(r); - } - } - - // Put midi regions on midi tracks - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) { - return; - } - - nmiditracks = u_endian_read2(&ptfunxored[k-4], is_bigendian); - - for (tr = 0; tr < nmiditracks; tr++) { - char miditrackname[256]; - uint8_t namelen; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) { - return; - } - - namelen = ptfunxored[k+9]; - for (i = 0; i < namelen; i++) { - miditrackname[i] = ptfunxored[k+13+i]; - } - miditrackname[namelen] = '\0'; - k += 13 + namelen; - nregions = u_endian_read2(&ptfunxored[k], is_bigendian); - - for (i = 0; (i < nregions) && (k < len); i++) { - k += 24; - - ridx = u_endian_read2(&ptfunxored[k], is_bigendian); - - k += 5; - - region_pos = u_endian_read5(&ptfunxored[k], is_bigendian); - - k += 20; - - track_t mtr; - mtr.name = string(miditrackname); - mtr.index = tr; - mtr.playlist = 0; - // Find the midi region with index 'ridx' - std::vector::iterator begin = midiregions.begin(); - std::vector::iterator finish = midiregions.end(); - std::vector::iterator mregion; - wav_t w = { std::string(""), 0, 0, 0 }; - std::vector m; - region_t r = { std::string(""), ridx, 0, 0, 0, w, m}; - if ((mregion = std::find(begin, finish, r)) != finish) { - mtr.reg = *mregion; - mtr.reg.startpos = labs(region_pos - mtr.reg.startpos); - miditracks.push_back(mtr); - } - } - } -} - -void -PTFFormat::parsemidi12(void) { - uint32_t i, k; - uint64_t tr, n_midi_events, zero_ticks; - uint64_t midi_pos, midi_len, max_pos, region_pos; - uint8_t midi_velocity, midi_note; - uint16_t ridx; - uint16_t nmiditracks, regionnumber = 0; - uint32_t nregions, mr; - - std::vector midichunks; - midi_ev_t m; - - k = 0; - - // Parse all midi chunks, not 1:1 mapping to regions yet - while (k + 35 < len) { - max_pos = 0; - std::vector midi; - - // Find MdNLB - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"MdNLB", 5)) { - break; - } - - k += 11; - n_midi_events = u_endian_read4(&ptfunxored[k], is_bigendian); - - k += 4; - zero_ticks = u_endian_read5(&ptfunxored[k], is_bigendian); - for (i = 0; i < n_midi_events && k < len; i++, k += 35) { - midi_pos = u_endian_read5(&ptfunxored[k], is_bigendian); - midi_pos -= zero_ticks; - midi_note = ptfunxored[k+8]; - midi_len = u_endian_read5(&ptfunxored[k+9], is_bigendian); - midi_velocity = ptfunxored[k+17]; - - if (midi_pos + midi_len > max_pos) { - max_pos = midi_pos + midi_len; - } - - m.pos = midi_pos; - m.length = midi_len; - m.note = midi_note; - m.velocity = midi_velocity; -#if 1 -// stop gap measure to prevent crashes in ardour, -// remove when decryption is fully solved for .ptx - if ((m.velocity & 0x80) || (m.note & 0x80) || - (m.pos & 0xff00000000LL) || (m.length & 0xff00000000LL)) { - continue; - } -#endif - midi.push_back(m); - } - midichunks.push_back(mchunk (zero_ticks, max_pos, midi)); - } - - // Map midi chunks to regions - while (k < len) { - char midiregionname[256]; - uint8_t namelen; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"MdTEL", 5)) { - break; - } - - k += 41; - - nregions = u_endian_read2(&ptfunxored[k], is_bigendian); - - for (mr = 0; mr < nregions; mr++) { - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x01", 2)) { - break; - } - k += 18; - - namelen = ptfunxored[k]; - for (i = 0; i < namelen; i++) { - midiregionname[i] = ptfunxored[k+4+i]; - } - midiregionname[namelen] = '\0'; - k += 4 + namelen; - - k += 5; - /* - region_pos = (uint64_t)ptfunxored[k] | - (uint64_t)ptfunxored[k+1] << 8 | - (uint64_t)ptfunxored[k+2] << 16 | - (uint64_t)ptfunxored[k+3] << 24 | - (uint64_t)ptfunxored[k+4] << 32; - */ - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xfe\xff\x00\x00", 4)) { - break; - } - - k += 37; - - ridx = u_endian_read2(&ptfunxored[k], is_bigendian); - - k += 3; - struct mchunk mc = *(midichunks.begin()+ridx); - - wav_t w = { std::string(""), 0, 0, 0 }; - region_t r = { - midiregionname, - regionnumber++, - //(int64_t)mc.zero, - (int64_t)0xe8d4a51000ULL, - (int64_t)(0), - //(int64_t)(max_pos*sessionrate*60/(960000*120)), - (int64_t)mc.maxlen, - w, - mc.chunk, - }; - midiregions.push_back(r); - } - } - - // Put midi regions on midi tracks - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) { - return; - } - - nmiditracks = u_endian_read2(&ptfunxored[k-4], is_bigendian); - - for (tr = 0; tr < nmiditracks; tr++) { - char miditrackname[256]; - uint8_t namelen; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) { - return; - } - - namelen = ptfunxored[k+9]; - for (i = 0; i < namelen; i++) { - miditrackname[i] = ptfunxored[k+13+i]; - } - miditrackname[namelen] = '\0'; - k += 13 + namelen; - nregions = u_endian_read2(&ptfunxored[k], is_bigendian); - - k += 13; - - for (i = 0; (i < nregions) && (k < len); i++) { - while (k < len) { - if ( (ptfunxored[k] == 0x5a) && - (ptfunxored[k+1] & 0x08)) { - break; - } - k++; - } - k += 11; - - ridx = u_endian_read2(&ptfunxored[k], is_bigendian); - - k += 5; - - region_pos = u_endian_read5(&ptfunxored[k], is_bigendian); - - track_t mtr; - mtr.name = string(miditrackname); - mtr.index = tr; - mtr.playlist = 0; - // Find the midi region with index 'ridx' - std::vector::iterator begin = midiregions.begin(); - std::vector::iterator finish = midiregions.end(); - std::vector::iterator mregion; - wav_t w = { std::string(""), 0, 0, 0 }; - std::vector m; - region_t r = { std::string(""), ridx, 0, 0, 0, w, m}; - if ((mregion = std::find(begin, finish, r)) != finish) { - mtr.reg = *mregion; - mtr.reg.startpos = labs(region_pos - mtr.reg.startpos); - miditracks.push_back(mtr); - } - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8)) { - return; - } - } - } -} - -void -PTFFormat::parseaudio(void) { - uint32_t i,j,k,l; - std::string wave; - - k = 0; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Audio Files", 11)) - return; - - // Find end of wav file list - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4)) - return; - - // Find number of wave files - uint16_t numberofwavs; - j = k; - if (!jumpback(&j, ptfunxored, len, (const unsigned char *)"\x5a\x01", 2)) - return; - - numberofwavs = u_endian_read4(&ptfunxored[j-4], is_bigendian); - //printf("%d wavs\n", numberofwavs); - - // Find actual wav names - char wavname[256]; - j = k - 2; - for (i = 0; i < numberofwavs; i++) { - while (j > 0) { - if ( ((ptfunxored[j ] == 'W') || (ptfunxored[j ] == 'A') || ptfunxored[j ] == '\0') && - ((ptfunxored[j-1] == 'A') || (ptfunxored[j-1] == 'I') || ptfunxored[j-1] == '\0') && - ((ptfunxored[j-2] == 'V') || (ptfunxored[j-2] == 'F') || ptfunxored[j-2] == '\0')) { - break; - } - j--; - } - j -= 4; - l = 0; - while (ptfunxored[j] != '\0') { - wavname[l] = ptfunxored[j]; - l++; - j--; - } - wavname[l] = '\0'; - - // Must be at least "vaw.z\0" - if (l < 6) { - i--; - continue; - } - - // and skip "zWAVE" or "zAIFF" - if ( ( (wavname[1] == 'W') && - (wavname[2] == 'A') && - (wavname[3] == 'V') && - (wavname[4] == 'E')) || - ( (wavname[1] == 'A') && - (wavname[2] == 'I') && - (wavname[3] == 'F') && - (wavname[4] == 'F'))) { - wave = string(&wavname[5]); - } else { - wave = string(wavname); - } - //uint8_t playlist = ptfunxored[j-8]; - - std::reverse(wave.begin(), wave.end()); - wav_t f = { wave, (uint16_t)(numberofwavs - i - 1), 0, 0 }; - - if (foundin(wave, string("Audio Files")) || - foundin(wave, string("Fade Files"))) { - i--; - continue; - } - - actualwavs.push_back(f); - audiofiles.push_back(f); - - //printf(" %d:%s \n", numberofwavs - i - 1, wave.c_str()); - } - std::reverse(audiofiles.begin(), audiofiles.end()); - std::reverse(actualwavs.begin(), actualwavs.end()); - //resort(audiofiles); - //resort(actualwavs); - - // Jump to end of wav file list - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4)) - return; - - // Loop through all the sources - for (vector::iterator w = audiofiles.begin(); w != audiofiles.end(); ++w) { - // Jump to start of source metadata for this source - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x07", 2)) - return; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) - return; - k++; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) - return; - - w->length = u_endian_read4(&ptfunxored[k-25], false); - } -} - -void -PTFFormat::parserest89(void) { - uint32_t i,j,k; - uint8_t startbytes = 0; - uint8_t lengthbytes = 0; - uint8_t offsetbytes = 0; - uint8_t somethingbytes = 0; - uint8_t skipbytes = 0; - - // Find Regions - k = 0; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Snap", 4)) { - return; - } - - uint16_t rindex = 0; - uint32_t findex = 0; - for (i = k; i < len-70; i++) { - if ( (ptfunxored[i ] == 0x5a) && - (ptfunxored[i+1] == 0x0a)) { - break; - } - if ( (ptfunxored[i ] == 0x5a) && - (ptfunxored[i+1] == 0x0c)) { - - uint8_t lengthofname = ptfunxored[i+9]; - - char name[256] = {0}; - for (j = 0; j < lengthofname; j++) { - name[j] = ptfunxored[i+13+j]; - } - name[j] = '\0'; - j += i+13; - //uint8_t disabled = ptfunxored[j]; - - offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4; - lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4; - startbytes = (ptfunxored[j+3] & 0xf0) >> 4; - somethingbytes = (ptfunxored[j+3] & 0xf); - skipbytes = ptfunxored[j+4]; - findex = ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes - +40]; - /*rindex = ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes - +24]; - */ - uint32_t sampleoffset = 0; - switch (offsetbytes) { - case 4: - sampleoffset = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - sampleoffset = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - sampleoffset = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - sampleoffset = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=offsetbytes; - uint32_t length = 0; - switch (lengthbytes) { - case 4: - length = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - length = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - length = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - length = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=lengthbytes; - uint32_t start = 0; - switch (startbytes) { - case 4: - start = u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - start = u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - start = (uint32_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - start = (uint32_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=startbytes; - /* - uint32_t something = 0; - switch (somethingbytes) { - case 4: - something |= (uint32_t)(ptfunxored[j+8] << 24); - case 3: - something |= (uint32_t)(ptfunxored[j+7] << 16); - case 2: - something |= (uint32_t)(ptfunxored[j+6] << 8); - case 1: - something |= (uint32_t)(ptfunxored[j+5]); - default: - break; - } - j+=somethingbytes; - */ - std::string filename = string(name); - wav_t f = { - filename, - (uint16_t)findex, - (int64_t)(start*ratefactor), - (int64_t)(length*ratefactor), - }; - - //printf("something=%d\n", something); - - vector::iterator begin = actualwavs.begin(); - vector::iterator finish = actualwavs.end(); - vector::iterator found; - // Add file to list only if it is an actual wav - if ((found = std::find(begin, finish, f)) != finish) { - f.filename = (*found).filename; - // Also add plain wav as region - std::vector m; - region_t r = { - name, - rindex, - (int64_t)(start*ratefactor), - (int64_t)(sampleoffset*ratefactor), - (int64_t)(length*ratefactor), - f, - m - }; - regions.push_back(r); - // Region only - } else { - if (foundin(filename, string(".grp"))) { - continue; - } - std::vector m; - region_t r = { - name, - rindex, - (int64_t)(start*ratefactor), - (int64_t)(sampleoffset*ratefactor), - (int64_t)(length*ratefactor), - f, - m - }; - regions.push_back(r); - } - rindex++; - } - } - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) { - return; - } - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) { - return; - } - k++; - - // Tracks - uint32_t offset; - uint32_t tracknumber = 0; - uint32_t regionspertrack = 0; - for (;k < len; k++) { - if ( (ptfunxored[k ] == 0x5a) && - (ptfunxored[k+1] == 0x04)) { - break; - } - if ( (ptfunxored[k ] == 0x5a) && - (ptfunxored[k+1] == 0x02)) { - - uint8_t lengthofname = 0; - lengthofname = ptfunxored[k+9]; - if (lengthofname == 0x5a) { - continue; - } - track_t tr; - - regionspertrack = (uint8_t)(ptfunxored[k+13+lengthofname]); - - //printf("regions/track=%d\n", regionspertrack); - char name[256] = {0}; - for (j = 0; j < lengthofname; j++) { - name[j] = ptfunxored[j+k+13]; - } - name[j] = '\0'; - tr.name = string(name); - tr.index = tracknumber++; - - for (j = k; regionspertrack > 0 && j < len; j++) { - jumpto(&j, ptfunxored, len, (const unsigned char *)"\x5a\x07", 2); - tr.reg.index = (uint16_t)(ptfunxored[j+11] & 0xff) - | (uint16_t)((ptfunxored[j+12] << 8) & 0xff00); - vector::iterator begin = regions.begin(); - vector::iterator finish = regions.end(); - vector::iterator found; - if ((found = std::find(begin, finish, tr.reg)) != finish) { - tr.reg = (*found); - } - i = j+16; - offset = u_endian_read4(&ptfunxored[i], is_bigendian); - tr.reg.startpos = (int64_t)(offset*ratefactor); - if (tr.reg.length > 0) { - tracks.push_back(tr); - } - regionspertrack--; - } - } - } -} - -void -PTFFormat::parserest12(void) { - uint32_t i,j,k,l,m,n; - uint8_t startbytes = 0; - uint8_t lengthbytes = 0; - uint8_t offsetbytes = 0; - uint8_t somethingbytes = 0; - uint8_t skipbytes = 0; - uint32_t maxregions = 0; - uint32_t findex = 0; - uint32_t findex2 = 0; - uint32_t findex3 = 0; - uint16_t rindex = 0; - vector groups; - uint16_t groupcount, compoundcount, groupmax; - uint16_t gindex, gindex2; - - m = 0; - n = 0; - vector groupmap; - // Find region group total - k = 0; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Custom 1\0\0\x5a", 11)) - goto nocustom; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4)) - return; - - if (!jumpback(&k, ptfunxored, len, (const unsigned char *)"\x5a", 1)) - return; - - jumpto(&k, ptfunxored, k+0x2000, (const unsigned char *)"\x5a\x03", 2); - k++; - - groupcount = 0; - for (i = k; i < len; i++) { - if (!jumpto(&i, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) - break; - groupcount++; - } - verbose_printf("groupcount=%d\n", groupcount); - - // Find start of group names -> group indexes - k = 0; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Custom 1\0\0\x5a", 11)) - return; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4)) - return; - - if (!jumpback(&k, ptfunxored, len, (const unsigned char *)"\x5a", 1)) - return; - k++; - - // Skip total number of groups - for (i = 0; i < groupcount; i++) { - while (k < len) { - if ( (ptfunxored[k ] == 0x5a) && - ((ptfunxored[k+1] == 0x03) || (ptfunxored[k+1] == 0x0a))) { - break; - } - k++; - } - k++; - } - - while (k < len) { - if ( (ptfunxored[k ] == 0x5a) && - (ptfunxored[k+1] & 0x02)) { - break; - } - k++; - } - k++; - - while (k < len) { - if ( (ptfunxored[k ] == 0x5a) && - (ptfunxored[k+1] & 0x02)) { - break; - } - k++; - } - k++; - - verbose_printf("start of groups k=0x%x\n", k); - // Loop over all groups and associate the compound index/name - for (i = 0; i < groupcount; i++) { - while (k < len) { - if ( (ptfunxored[k ] == 0x5a) && - (ptfunxored[k+1] & 0x02)) { - break; - } - k++; - } - if (k > len) - break; - gindex = u_endian_read2(&ptfunxored[k+9], is_bigendian); - gindex2 = u_endian_read2(&ptfunxored[k+3], is_bigendian); - - uint8_t lengthofname = ptfunxored[k+13]; - char name[256] = {0}; - for (l = 0; l < lengthofname; l++) { - name[l] = ptfunxored[k+17+l]; - } - name[l] = '\0'; - - if (strlen(name) == 0) { - i--; - k++; - continue; - } - compound_t c = { - (uint16_t)i, // curr_index - gindex, // unknown1 - 0, // level - 0, // ontopof_index - gindex2, // next_index - string(name) - }; - groupmap.push_back(c); - k++; - } - - // Sort lookup table by group index - //std::sort(glookup.begin(), glookup.end(), regidx_compare); - - // print compounds as flattened tree - j = 0; - for (std::vector::iterator i = groupmap.begin(); i != groupmap.end(); ++i) { - verbose_printf("g(%u) uk(%u) ni(%u) %s\n", i->curr_index, i->unknown1, i->next_index, i->name.c_str()); - j++; - } - -nocustom: - // Find region groups - k = 0; - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Snap", 4)) - return; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x06", 2)) - return; - k++; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) - return; - k++; - - if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) - return; - k++; - - // Hack to find actual start of region group information - while (k < len) { - if ((ptfunxored[k+13] == 0x5a) && (ptfunxored[k+14] & 0xf)) { - k += 13; - continue; - } else { - if ((ptfunxored[k+9] == 0x5a) && (ptfunxored[k+10] & 0xf)) { - k += 9; - continue; - } - } - if ((ptfunxored[k] == 0x5a) && (ptfunxored[k+1] & 0xf)) - break; - k++; - } - verbose_printf("hack region groups k=0x%x\n", k); - - compoundcount = 0; - j = k; - groupmax = groupcount == 0 ? 0 : u_endian_read2(&ptfunxored[j+3], is_bigendian); - groupcount = 0; - for (i = k; (groupcount < groupmax) && (i < len-70); i++) { - if ( (ptfunxored[i ] == 0x5a) && - (ptfunxored[i+1] == 0x03)) { - break; - } - if ( (ptfunxored[i ] == 0x5a) && - ((ptfunxored[i+1] == 0x01) || (ptfunxored[i+1] == 0x02))) { - - //findex = ptfunxored[i-48] | ptfunxored[i-47] << 8; - //rindex = ptfunxored[i+3] | ptfunxored[i+4] << 8; - - uint8_t lengthofname = ptfunxored[i+9]; - if (ptfunxored[i+13] == 0x5a) { - continue; - } - char name[256] = {0}; - for (j = 0; j < lengthofname; j++) { - name[j] = ptfunxored[i+13+j]; - } - name[j] = '\0'; - j += i+13; - - offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4; - lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4; - startbytes = (ptfunxored[j+3] & 0xf0) >> 4; - somethingbytes = (ptfunxored[j+3] & 0xf); - skipbytes = ptfunxored[j+4]; - uint16_t regionsingroup = ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes - +12] - | ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes - +13] << 8; - - findex = ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes - +37] - | ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes - +38] << 8; - - uint64_t sampleoffset = 0; - switch (offsetbytes) { - case 5: - sampleoffset = u_endian_read5(&ptfunxored[j+5], false); - break; - case 4: - sampleoffset = (uint64_t)u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - sampleoffset = (uint64_t)u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - sampleoffset = (uint64_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - sampleoffset = (uint64_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=offsetbytes; - uint64_t length = 0; - switch (lengthbytes) { - case 5: - length = u_endian_read5(&ptfunxored[j+5], false); - break; - case 4: - length = (uint64_t)u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - length = (uint64_t)u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - length = (uint64_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - length = (uint64_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=lengthbytes; - uint64_t start = 0; - switch (startbytes) { - case 5: - start = u_endian_read5(&ptfunxored[j+5], false); - break; - case 4: - start = (uint64_t)u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - start = (uint64_t)u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - start = (uint64_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - start = (uint64_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=startbytes; - - if (offsetbytes == 5) - sampleoffset -= 1000000000000ULL; - if (startbytes == 5) - start -= 1000000000000ULL; - - std::string filename = string(name); - wav_t f = { - filename, - (uint16_t)findex, - (int64_t)(start*ratefactor), - (int64_t)(length*ratefactor), - }; - - if (strlen(name) == 0) { - continue; - } - if (length == 0) { - continue; - } - //if (foundin(filename, string(".grp")) && !regionsingroup && !findex) { - // // Empty region group - // verbose_printf(" EMPTY: %s\n", name); - // continue; - if (regionsingroup) { - // Active region grouping - // Iterate parsing all the regions in the group - verbose_printf("\nGROUP\t%d %s\n", groupcount, name); - m = j; - n = j+16; - - for (l = 0; l < regionsingroup; l++) { - if (!jumpto(&n, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) { - return; - } - n++; - } - n--; - //printf("n=0x%x\n", n+112); - //findex = ptfunxored[n+112] | (ptfunxored[n+113] << 8); - findex = u_endian_read2(&ptfunxored[i-11], is_bigendian); - findex2 = u_endian_read2(&ptfunxored[n+108], is_bigendian); - //findex2= rindex; //XXX - // Find wav with correct findex - vector::iterator wave = actualwavs.end(); - for (vector::iterator aw = actualwavs.begin(); - aw != actualwavs.end(); ++aw) { - if (aw->index == findex) { - wave = aw; - } - } - if (wave == actualwavs.end()) - return; - - if (!jumpto(&n, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) - return; - n += 37; - //rindex = ptfunxored[n] | (ptfunxored[n+1] << 8); - for (l = 0; l < regionsingroup; l++) { - if (!jumpto(&m, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) - return; - - m += 37; - rindex = u_endian_read2(&ptfunxored[m], is_bigendian); - - m += 12; - sampleoffset = 0; - switch (offsetbytes) { - case 5: - sampleoffset = u_endian_read5(&ptfunxored[m], false); - break; - case 4: - sampleoffset = (uint64_t)u_endian_read4(&ptfunxored[m], false); - break; - case 3: - sampleoffset = (uint64_t)u_endian_read3(&ptfunxored[m], false); - break; - case 2: - sampleoffset = (uint64_t)u_endian_read2(&ptfunxored[m], false); - break; - case 1: - sampleoffset = (uint64_t)(ptfunxored[m]); - break; - default: - break; - } - m+=offsetbytes+3; - start = 0; - switch (offsetbytes) { - case 5: - start = u_endian_read5(&ptfunxored[m], false); - break; - case 4: - start = (uint64_t)u_endian_read4(&ptfunxored[m], false); - break; - case 3: - start = (uint64_t)u_endian_read3(&ptfunxored[m], false); - break; - case 2: - start = (uint64_t)u_endian_read2(&ptfunxored[m], false); - break; - case 1: - start = (uint64_t)(ptfunxored[m]); - break; - default: - break; - } - m+=offsetbytes+3; - length = 0; - switch (lengthbytes) { - case 5: - length = u_endian_read5(&ptfunxored[m], false); - break; - case 4: - length = (uint64_t)u_endian_read4(&ptfunxored[m], false); - break; - case 3: - length = (uint64_t)u_endian_read3(&ptfunxored[m], false); - break; - case 2: - length = (uint64_t)u_endian_read2(&ptfunxored[m], false); - break; - case 1: - length = (uint64_t)(ptfunxored[m]); - break; - default: - break; - } - m+=8; - findex3 = ptfunxored[m] | (ptfunxored[m+1] << 8); - sampleoffset -= 1000000000000ULL; - start -= 1000000000000ULL; - - /* - // Find wav with correct findex - vector::iterator wave = actualwavs.end(); - for (vector::iterator aw = actualwavs.begin(); - aw != actualwavs.end(); ++aw) { - if (aw->index == (glookup.begin()+findex2)->startpos) { - wave = aw; - } - } - if (wave == actualwavs.end()) - return; - // findex is the true source - std::vector md; - region_t r = { - name, - (uint16_t)rindex, - (int64_t)findex, //(start*ratefactor), - (int64_t)findex2, //(sampleoffset*ratefactor), - (int64_t)findex3, //(length*ratefactor), - *wave, - md - }; - groups.push_back(r); - */ - vector::iterator g = groupmap.begin()+findex2; - if (g >= groupmap.end()) - continue; - compound_t c; - c.name = string(g->name); - c.curr_index = compoundcount; - c.level = findex; - c.ontopof_index = findex3; - c.next_index = g->next_index; - c.unknown1 = g->unknown1; - compounds.push_back(c); - verbose_printf("COMPOUND\tc(%d) %s (%d %d) -> c(%u) %s\n", c.curr_index, c.name.c_str(), c.level, c.ontopof_index, c.next_index, name); - compoundcount++; - } - groupcount++; - } - } - } - j = 0; - - // Start pure regions - k = m != 0 ? m : k - 1; - if (!jumpto(&k, ptfunxored, k+64, (const unsigned char *)"\x5a\x05", 2)) - jumpto(&k, ptfunxored, k+0x400, (const unsigned char *)"\x5a\x02", 2); - - verbose_printf("pure regions k=0x%x\n", k); - - maxregions = u_endian_read4(&ptfunxored[k-4], is_bigendian); - - verbose_printf("maxregions=%u\n", maxregions); - rindex = 0; - for (i = k; rindex < maxregions && i < len; i++) { - if ( (ptfunxored[i ] == 0xff) && - (ptfunxored[i+1] == 0x5a) && - (ptfunxored[i+2] == 0x01)) { - break; - } - //if ( (ptfunxored[i ] == 0x5a) && - // (ptfunxored[i+1] == 0x03)) { - // break; - //} - if ( (ptfunxored[i ] == 0x5a) && - ((ptfunxored[i+1] == 0x01) || (ptfunxored[i+1] == 0x02))) { - - //findex = ptfunxored[i-48] | ptfunxored[i-47] << 8; - //rindex = ptfunxored[i+3] | ptfunxored[i+4] << 8; - - uint8_t lengthofname = ptfunxored[i+9]; - if (ptfunxored[i+13] == 0x5a) { - continue; - } - char name[256] = {0}; - for (j = 0; j < lengthofname; j++) { - name[j] = ptfunxored[i+13+j]; - } - name[j] = '\0'; - j += i+13; - - offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4; - lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4; - startbytes = (ptfunxored[j+3] & 0xf0) >> 4; - somethingbytes = (ptfunxored[j+3] & 0xf); - skipbytes = ptfunxored[j+4]; - findex = ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes - +37] - | ptfunxored[j+5 - +startbytes - +lengthbytes - +offsetbytes - +somethingbytes - +skipbytes - +38] << 8; - - uint64_t sampleoffset = 0; - switch (offsetbytes) { - case 5: - sampleoffset = u_endian_read5(&ptfunxored[j+5], false); - break; - case 4: - sampleoffset = (uint64_t)u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - sampleoffset = (uint64_t)u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - sampleoffset = (uint64_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - sampleoffset = (uint64_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=offsetbytes; - uint64_t length = 0; - switch (lengthbytes) { - case 5: - length = u_endian_read5(&ptfunxored[j+5], false); - break; - case 4: - length = (uint64_t)u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - length = (uint64_t)u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - length = (uint64_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - length = (uint64_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=lengthbytes; - uint64_t start = 0; - switch (startbytes) { - case 5: - start = u_endian_read5(&ptfunxored[j+5], false); - break; - case 4: - start = (uint64_t)u_endian_read4(&ptfunxored[j+5], false); - break; - case 3: - start = (uint64_t)u_endian_read3(&ptfunxored[j+5], false); - break; - case 2: - start = (uint64_t)u_endian_read2(&ptfunxored[j+5], false); - break; - case 1: - start = (uint64_t)(ptfunxored[j+5]); - break; - default: - break; - } - j+=startbytes; - - if (offsetbytes == 5) - sampleoffset -= 1000000000000ULL; - if (startbytes == 5) - start -= 1000000000000ULL; - - std::string filename = string(name); - wav_t f = { - filename, - (uint16_t)findex, - (int64_t)(start*ratefactor), - (int64_t)(length*ratefactor), - }; - - if (strlen(name) == 0) { - continue; - } - if (length == 0) { - continue; - } - // Regular region mapping to a source - uint32_t n = j; - if (!jumpto(&n, ptfunxored, len, (const unsigned char *)"\x5a\x01", 2)) - return; - //printf("XXX=%d\n", ptfunxored[n+12] | ptfunxored[n+13]<<8); - - // Find wav with correct findex - vector::iterator wave = actualwavs.end(); - for (vector::iterator aw = actualwavs.begin(); - aw != actualwavs.end(); ++aw) { - if (aw->index == findex) { - wave = aw; - } - } - if (wave == actualwavs.end()) { - verbose_printf("missing source with findex\n"); - continue; - } - //verbose_printf("\n+r(%d) w(%d) REGION: %s st(%lx)x%u of(%lx)x%u ln(%lx)x%u\n", rindex, findex, name, start, startbytes, sampleoffset, offsetbytes, length, lengthbytes); - verbose_printf("REGION\tg(NA)\tr(%d)\tw(%d) %s(%s)\n", rindex, findex, name, wave->filename.c_str()); - std::vector md; - region_t r = { - name, - rindex, - (int64_t)(start*ratefactor), - (int64_t)(sampleoffset*ratefactor), - (int64_t)(length*ratefactor), - *wave, - md - }; - regions.push_back(r); - rindex++; - } - } - - // print compounds - vector rootnodes; - bool found = false; - - j = 0; - for (vector::iterator cmp = compounds.begin(); - cmp != compounds.end(); ++cmp) { - found = false; - for (vector::iterator tmp = compounds.begin(); - tmp != compounds.end(); ++tmp) { - if (tmp == cmp) - continue; - if (tmp->ontopof_index == cmp->curr_index) - found = true; - } - // Collect a vector of all the root nodes (no others point to) - if (!found) - rootnodes.push_back(cmp->curr_index); - } - - for (vector::iterator rt = rootnodes.begin(); - rt != rootnodes.end(); ++rt) { - vector::iterator cmp = compounds.begin()+(*rt); - // Now we are at a root node, follow to leaf - if (cmp >= compounds.end()) - continue; - - verbose_printf("----\n"); - - for (; cmp < compounds.end() && cmp->curr_index != cmp->next_index; - cmp = compounds.begin()+cmp->next_index) { - - // Find region - vector::iterator r = regions.end(); - for (vector::iterator rs = regions.begin(); - rs != regions.end(); rs++) { - if (rs->index == cmp->unknown1 + cmp->level) { - r = rs; - } - } - if (r == regions.end()) - continue; - verbose_printf("\t->cidx(%u) pl(%u)+ridx(%u) cflags(0x%x) ?(%u) grp(%s) reg(%s)\n", cmp->curr_index, cmp->level, cmp->unknown1, cmp->ontopof_index, cmp->next_index, cmp->name.c_str(), r->name.c_str()); - } - // Find region - vector::iterator r = regions.end(); - for (vector::iterator rs = regions.begin(); - rs != regions.end(); rs++) { - if (rs->index == cmp->unknown1 + cmp->level) { - r = rs; - } - } - if (r == regions.end()) - continue; - verbose_printf("\tLEAF->cidx(%u) pl(%u)+ridx(%u) cflags(0x%x) ?(%u) grp(%s) reg(%s)\n", cmp->curr_index, cmp->level, cmp->unknown1, cmp->ontopof_index, cmp->next_index, cmp->name.c_str(), r->name.c_str()); - } - - // Start grouped regions - - // Print region groups mapped to sources - for (vector::iterator a = groups.begin(); a != groups.end(); ++a) { - // Find wav with findex - vector::iterator wav = audiofiles.end(); - for (vector::iterator ws = audiofiles.begin(); - ws != audiofiles.end(); ws++) { - if (ws->index == a->startpos) { - wav = ws; - } - } - if (wav == audiofiles.end()) - continue; - - // Find wav with findex2 - vector::iterator wav2 = audiofiles.end(); - for (vector::iterator ws = audiofiles.begin(); - ws != audiofiles.end(); ws++) { - if (ws->index == a->sampleoffset) { - wav2 = ws; - } - } - if (wav2 == audiofiles.end()) - continue; - - verbose_printf("Group: %s -> %s OR %s\n", a->name.c_str(), wav->filename.c_str(), wav2->filename.c_str()); - } - - //filter(regions); - //resort(regions); - - // Tracks - uint32_t offset; - uint32_t tracknumber = 0; - uint32_t regionspertrack = 0; - - // Total tracks - j = k; - if (!jumpto(&j, ptfunxored, len, (const unsigned char *)"\x5a\x03\x00", 3)) - return; - //maxtracks = u_endian_read4(&ptfunxored[j-4]); - - // Jump to start of region -> track mappings - if (jumpto(&k, ptfunxored, k + regions.size() * 0x400, (const unsigned char *)"\x5a\x08", 2)) { - if (!jumpback(&k, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) - return; - } else if (jumpto(&k, ptfunxored, k + regions.size() * 0x400, (const unsigned char *)"\x5a\x0a", 2)) { - if (!jumpback(&k, ptfunxored, len, (const unsigned char *)"\x5a\x01", 2)) - return; - } else { - return; - } - verbose_printf("tracks k=0x%x\n", k); - - for (;k < len; k++) { - if ( (ptfunxored[k ] == 0x5a) && - (ptfunxored[k+1] & 0x04)) { - break; - } - if ( (ptfunxored[k ] == 0x5a) && - (ptfunxored[k+1] & 0x02)) { - - uint8_t lengthofname = 0; - lengthofname = ptfunxored[k+9]; - if (lengthofname == 0x5a) { - continue; - } - track_t tr; - - regionspertrack = (uint8_t)(ptfunxored[k+13+lengthofname]); - - //printf("regions/track=%d\n", regionspertrack); - char name[256] = {0}; - for (j = 0; j < lengthofname; j++) { - name[j] = ptfunxored[j+k+13]; - } - name[j] = '\0'; - tr.name = string(name); - tr.index = tracknumber++; - - for (j = k+18+lengthofname; regionspertrack > 0 && j < len; j++) { - jumpto(&j, ptfunxored, len, (const unsigned char *)"\x5a", 1); - bool isgroup = ptfunxored[j+27] > 0; - if (isgroup) { - tr.reg.name = string(""); - tr.reg.length = 0; - //tr.reg.index = 0xffff; - verbose_printf("TRACK: t(%d) g(%d) G(%s) -> T(%s)\n", - tracknumber, tr.reg.index, tr.reg.name.c_str(), tr.name.c_str()); - } else { - tr.reg.index = ((uint16_t)(ptfunxored[j+11]) & 0xff) - | (((uint16_t)(ptfunxored[j+12]) << 8) & 0xff00); - vector::iterator begin = regions.begin(); - vector::iterator finish = regions.end(); - vector::iterator found; - if ((found = std::find(begin, finish, tr.reg)) != finish) { - tr.reg = *found; - } - verbose_printf("TRACK: t(%d) r(%d) R(%s) -> T(%s)\n", - tracknumber, tr.reg.index, tr.reg.name.c_str(), tr.name.c_str()); - } - i = j+16; - offset = u_endian_read4(&ptfunxored[i], is_bigendian); - tr.reg.startpos = (int64_t)(offset*ratefactor); - if (tr.reg.length > 0) { - tracks.push_back(tr); - } - regionspertrack--; - - jumpto(&j, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); - j += 12; - } - } - } -} diff --git a/libs/ptformat/ptformat.cc b/libs/ptformat/ptformat.cc new file mode 100644 index 0000000000..b6b13b745f --- /dev/null +++ b/libs/ptformat/ptformat.cc @@ -0,0 +1,1350 @@ +/* + * libptformat - a library to read ProTools sessions + * + * Copyright (C) 2015-2019 Damien Zammit + * Copyright (C) 2015-2019 Robin Gareus + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include + +#ifdef HAVE_GLIB +# include +# define ptf_open g_fopen +#else +# define ptf_open fopen +#endif + +#include "ptformat/ptformat.h" + +#define BITCODE "0010111100101011" +#define ZMARK '\x5a' +#define ZERO_TICKS 0xe8d4a51000ULL +#define MAX_CONTENT_TYPE 0x3000 +#define MAX_CHANNELS_PER_TRACK 8 + +#if 0 +#define DEBUG +#endif + +#ifdef DEBUG +#define verbose_printf(...) printf("XXX PTFORMAT XXX: " __VA_ARGS__) +#else +#define verbose_printf(...) +#endif + +using namespace std; + +static void +hexdump(uint8_t *data, int length, int level) +{ + int i,j,k,end,step=16; + + for (i = 0; i < length; i += step) { + end = i + step; + if (end > length) end = length; + for (k = 0; k < level; k++) + printf(" "); + for (j = i; j < end; j++) { + printf("%02X ", data[j]); + } + for (j = i; j < end; j++) { + if (data[j] < 128 && data[j] > 32) + printf("%c", data[j]); + else + printf("."); + } + printf("\n"); + } +} + +PTFFormat::PTFFormat() + : _ptfunxored(0) + , _len(0) + , _sessionrate(0) + , _version(0) + , _product(NULL) + , _targetrate (0) + , _ratefactor (1.0) + , is_bigendian(false) +{ +} + +PTFFormat::~PTFFormat() { + cleanup(); +} + +const std::string +PTFFormat::get_content_description(uint16_t ctype) { + switch(ctype) { + case 0x0030: + return std::string("INFO product and version"); + case 0x1001: + return std::string("WAV samplerate, size"); + case 0x1003: + return std::string("WAV metadata"); + case 0x1004: + return std::string("WAV list full"); + case 0x1007: + return std::string("region name, number"); + case 0x1008: + return std::string("AUDIO region name, number (v5)"); + case 0x100b: + return std::string("AUDIO region list (v5)"); + case 0x100f: + return std::string("AUDIO region->track entry"); + case 0x1011: + return std::string("AUDIO region->track map entries"); + case 0x1012: + return std::string("AUDIO region->track full map"); + case 0x1014: + return std::string("AUDIO track name, number"); + case 0x1015: + return std::string("AUDIO tracks"); + case 0x1017: + return std::string("PLUGIN entry"); + case 0x1018: + return std::string("PLUGIN full list"); + case 0x1021: + return std::string("I/O channel entry"); + case 0x1022: + return std::string("I/O channel list"); + case 0x1028: + return std::string("INFO sample rate"); + case 0x103a: + return std::string("WAV names"); + case 0x104f: + return std::string("AUDIO region->track subentry (v8)"); + case 0x1050: + return std::string("AUDIO region->track entry (v8)"); + case 0x1052: + return std::string("AUDIO region->track map entries (v8)"); + case 0x1054: + return std::string("AUDIO region->track full map (v8)"); + case 0x1056: + return std::string("MIDI region->track entry"); + case 0x1057: + return std::string("MIDI region->track map entries"); + case 0x1058: + return std::string("MIDI region->track full map"); + case 0x2000: + return std::string("MIDI events block"); + case 0x2001: + return std::string("MIDI region name, number (v5)"); + case 0x2002: + return std::string("MIDI regions map (v5)"); + case 0x2067: + return std::string("INFO path of session"); + case 0x2511: + return std::string("Snaps block"); + case 0x2519: + return std::string("MIDI track full list"); + case 0x251a: + return std::string("MIDI track name, number"); + case 0x2523: + return std::string("COMPOUND region element"); + case 0x2602: + return std::string("I/O route"); + case 0x2603: + return std::string("I/O routing table"); + case 0x2628: + return std::string("COMPOUND region group"); + case 0x2629: + return std::string("AUDIO region name, number (v10)"); + case 0x262a: + return std::string("AUDIO region list (v10)"); + case 0x262c: + return std::string("COMPOUND region full map"); + case 0x2633: + return std::string("MIDI regions name, number (v10)"); + case 0x2634: + return std::string("MIDI regions map (v10)"); + case 0x271a: + return std::string("MARKER list"); + default: + return std::string("UNKNOWN content type"); + } +} + +uint16_t +PTFFormat::u_endian_read2(unsigned char *buf, bool bigendian) +{ + if (bigendian) { + return ((uint16_t)(buf[0]) << 8) | (uint16_t)(buf[1]); + } else { + return ((uint16_t)(buf[1]) << 8) | (uint16_t)(buf[0]); + } +} + +uint32_t +PTFFormat::u_endian_read3(unsigned char *buf, bool bigendian) +{ + if (bigendian) { + return ((uint32_t)(buf[0]) << 16) | + ((uint32_t)(buf[1]) << 8) | + (uint32_t)(buf[2]); + } else { + return ((uint32_t)(buf[2]) << 16) | + ((uint32_t)(buf[1]) << 8) | + (uint32_t)(buf[0]); + } +} + +uint32_t +PTFFormat::u_endian_read4(unsigned char *buf, bool bigendian) +{ + if (bigendian) { + return ((uint32_t)(buf[0]) << 24) | + ((uint32_t)(buf[1]) << 16) | + ((uint32_t)(buf[2]) << 8) | + (uint32_t)(buf[3]); + } else { + return ((uint32_t)(buf[3]) << 24) | + ((uint32_t)(buf[2]) << 16) | + ((uint32_t)(buf[1]) << 8) | + (uint32_t)(buf[0]); + } +} + +uint64_t +PTFFormat::u_endian_read5(unsigned char *buf, bool bigendian) +{ + if (bigendian) { + return ((uint64_t)(buf[0]) << 32) | + ((uint64_t)(buf[1]) << 24) | + ((uint64_t)(buf[2]) << 16) | + ((uint64_t)(buf[3]) << 8) | + (uint64_t)(buf[4]); + } else { + return ((uint64_t)(buf[4]) << 32) | + ((uint64_t)(buf[3]) << 24) | + ((uint64_t)(buf[2]) << 16) | + ((uint64_t)(buf[1]) << 8) | + (uint64_t)(buf[0]); + } +} + +uint64_t +PTFFormat::u_endian_read8(unsigned char *buf, bool bigendian) +{ + if (bigendian) { + return ((uint64_t)(buf[0]) << 56) | + ((uint64_t)(buf[1]) << 48) | + ((uint64_t)(buf[2]) << 40) | + ((uint64_t)(buf[3]) << 32) | + ((uint64_t)(buf[4]) << 24) | + ((uint64_t)(buf[5]) << 16) | + ((uint64_t)(buf[6]) << 8) | + (uint64_t)(buf[7]); + } else { + return ((uint64_t)(buf[7]) << 56) | + ((uint64_t)(buf[6]) << 48) | + ((uint64_t)(buf[5]) << 40) | + ((uint64_t)(buf[4]) << 32) | + ((uint64_t)(buf[3]) << 24) | + ((uint64_t)(buf[2]) << 16) | + ((uint64_t)(buf[1]) << 8) | + (uint64_t)(buf[0]); + } +} + +void +PTFFormat::cleanup(void) { + _len = 0; + _sessionrate = 0; + _version = 0; + free(_ptfunxored); + _ptfunxored = NULL; + free (_product); + _product = NULL; + _audiofiles.clear(); + _regions.clear(); + _midiregions.clear(); + _tracks.clear(); + _miditracks.clear(); + free_all_blocks(); +} + +int64_t +PTFFormat::foundat(unsigned char *haystack, uint64_t n, const char *needle) { + int64_t found = 0; + uint64_t i, j, needle_n; + needle_n = strlen(needle); + + for (i = 0; i < n; i++) { + found = i; + for (j = 0; j < needle_n; j++) { + if (haystack[i+j] != needle[j]) { + found = -1; + break; + } + } + if (found > 0) + return found; + } + return -1; +} + +bool +PTFFormat::jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) { + uint64_t i; + uint64_t k = *currpos; + while (k + needlelen < maxoffset) { + bool foundall = true; + for (i = 0; i < needlelen; i++) { + if (buf[k+i] != needle[i]) { + foundall = false; + break; + } + } + if (foundall) { + *currpos = k; + return true; + } + k++; + } + return false; +} + +bool +PTFFormat::jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) { + uint64_t i; + uint64_t k = *currpos; + while (k > 0 && k + needlelen < maxoffset) { + bool foundall = true; + for (i = 0; i < needlelen; i++) { + if (buf[k+i] != needle[i]) { + foundall = false; + break; + } + } + if (foundall) { + *currpos = k; + return true; + } + k--; + } + return false; +} + +bool +PTFFormat::foundin(std::string const& haystack, std::string const& needle) { + size_t found = haystack.find(needle); + if (found != std::string::npos) { + return true; + } else { + return false; + } +} + +/* Return values: 0 success + -1 error decrypting pt session +*/ +int +PTFFormat::unxor(std::string const& path) { + FILE *fp; + unsigned char xxor[256]; + unsigned char ct; + uint64_t i; + uint8_t xor_type; + uint8_t xor_value; + uint8_t xor_delta; + uint16_t xor_len; + + if (! (fp = ptf_open(path.c_str(), "rb"))) { + return -1; + } + + fseek(fp, 0, SEEK_END); + _len = ftell(fp); + if (_len < 0x14) { + fclose(fp); + return -1; + } + + if (! (_ptfunxored = (unsigned char*) malloc(_len * sizeof(unsigned char)))) { + /* Silently fail -- out of memory*/ + fclose(fp); + _ptfunxored = 0; + return -1; + } + + /* The first 20 bytes are always unencrypted */ + fseek(fp, 0x00, SEEK_SET); + i = fread(_ptfunxored, 1, 0x14, fp); + if (i < 0x14) { + fclose(fp); + return -1; + } + + xor_type = _ptfunxored[0x12]; + xor_value = _ptfunxored[0x13]; + xor_len = 256; + + // xor_type 0x01 = ProTools 5, 6, 7, 8 and 9 + // xor_type 0x05 = ProTools 10, 11, 12 + switch(xor_type) { + case 0x01: + xor_delta = gen_xor_delta(xor_value, 53, false); + break; + case 0x05: + xor_delta = gen_xor_delta(xor_value, 11, true); + break; + default: + fclose(fp); + return -1; + } + + /* Generate the xor_key */ + for (i=0; i < xor_len; i++) + xxor[i] = (i * xor_delta) & 0xff; + + /* hexdump(xxor, xor_len); */ + + /* Read file and decrypt rest of file */ + i = 0x14; + fseek(fp, i, SEEK_SET); + while (fread(&ct, 1, 1, fp) != 0) { + uint8_t xor_index = (xor_type == 0x01) ? i & 0xff : (i >> 12) & 0xff; + _ptfunxored[i++] = ct ^ xxor[xor_index]; + } + fclose(fp); + return 0; +} + +/* Return values: 0 success + -1 error decrypting pt session + -2 error detecting pt session + -3 incompatible pt version + -4 error parsing pt session +*/ +int +PTFFormat::load(std::string const& ptf, int64_t targetsr) { + cleanup(); + _path = ptf; + + if (unxor(_path)) + return -1; + + if (parse_version()) + return -2; + + if (_version < 5 || _version > 12) + return -3; + + _targetrate = targetsr; + + int err = 0; + if ((err = parse())) { + printf ("PARSE FAILED %d\n", err); + return -4; + } + + return 0; +} + +bool +PTFFormat::parse_version() { + uint32_t seg_len,str_len; + uint8_t *data = _ptfunxored + 0x14; + uintptr_t data_end = ((uintptr_t)_ptfunxored) + 0x100; + uint8_t seg_type; + bool success = false; + + if (_ptfunxored[0] != '\x03' && foundat(_ptfunxored, 0x100, BITCODE) != 1) { + return false; + } + + while( ((uintptr_t)data < data_end) && (success == false) ) { + + if (data[0] != 0x5a) { + success = false; + break; + } + + seg_type = data[1]; + /* Skip segment header */ + data += 3; + if (data[0] == 0 && data[1] == 0) { + /* BE */ + is_bigendian = true; + } else { + /* LE */ + is_bigendian = false; + } + seg_len = u_endian_read4(&data[0], is_bigendian); + + /* Skip seg_len */ + data += 4; + if (!(seg_type == 0x04 || seg_type == 0x03) || data[0] != 0x03) { + /* Go to next segment */ + data += seg_len; + continue; + } + /* Skip 0x03 0x00 0x00 */ + data += 3; + seg_len -= 3; + str_len = (*(uint8_t *)data); + if (! (_product = (uint8_t *)malloc((str_len+1) * sizeof(uint8_t)))) { + success = false; + break; + } + + /* Skip str_len */ + data += 4; + seg_len -= 4; + + memcpy(_product, data, str_len); + _product[str_len] = 0; + data += str_len; + seg_len -= str_len; + + /* Skip 0x03 0x00 0x00 0x00 */ + data += 4; + seg_len -= 4; + + _version = data[0]; + if (_version == 0) { + _version = data[3]; + } + data += seg_len; + success = true; + } + + /* If the above does not work, try other heuristics */ + if ((uintptr_t)data >= data_end - seg_len) { + _version = _ptfunxored[0x40]; + if (_version == 0) { + _version = _ptfunxored[0x3d]; + } + if (_version == 0) { + _version = _ptfunxored[0x3a] + 2; + } + if (_version != 0) { + success = true; + } + } + return (!success); +} + +uint8_t +PTFFormat::gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative) { + uint16_t i; + for (i = 0; i < 256; i++) { + if (((i * mul) & 0xff) == xor_value) { + return (negative) ? i * (-1) : i; + } + } + // Should not occur + return 0; +} + +void +PTFFormat::setrates(void) { + _ratefactor = 1.f; + if (_sessionrate != 0) { + _ratefactor = (float)_targetrate / _sessionrate; + } +} + +bool +PTFFormat::parse_block_at(uint32_t pos, struct block_t *block, struct block_t *parent, int level) { + struct block_t b; + int childjump = 0; + uint32_t i; + uint32_t max = _len; + + if (_ptfunxored[pos] != ZMARK) + return false; + + if (parent) + max = parent->block_size + parent->offset; + + b.zmark = ZMARK; + b.block_type = u_endian_read2(&_ptfunxored[pos+1], is_bigendian); + b.block_size = u_endian_read4(&_ptfunxored[pos+3], is_bigendian); + b.content_type = u_endian_read2(&_ptfunxored[pos+7], is_bigendian); + b.offset = pos + 7; + + if (b.block_size + b.offset > max) + return false; + if (b.block_type & 0xff00) + return false; + + block->zmark = b.zmark; + block->block_type = b.block_type; + block->block_size = b.block_size; + block->content_type = b.content_type; + block->offset = b.offset; + memset(&block->child, 0, sizeof(block->child)); + + for (i = 1; (i < block->block_size) && (pos + i + childjump < max); i += childjump ? childjump : 1) { + int p = pos + i; + struct block_t bchild; + childjump = 0; + if (parse_block_at(p, &bchild, block, level+1)) { + block->child.push_back(bchild); + childjump = bchild.block_size + 7; + } + } + return true; +} + +void +PTFFormat::dump_block(struct block_t& b, int level) +{ + int i; + + for (i = 0; i < level; i++) { + printf(" "); + } + printf("%s(0x%04x)\n", get_content_description(b.content_type).c_str(), b.content_type); + hexdump(&_ptfunxored[b.offset], b.block_size, level); + + for (vector::iterator c = b.child.begin(); + c != b.child.end(); ++c) { + dump_block(*c, level + 1); + } +} + +void +PTFFormat::free_block(struct block_t& b) +{ + for (vector::iterator c = b.child.begin(); + c != b.child.end(); ++c) { + free_block(*c); + } + + b.child.clear(); +} + +void +PTFFormat::free_all_blocks(void) +{ + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + free_block(*b); + } + + blocks.clear(); +} + +void +PTFFormat::dump(void) { + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + dump_block(*b, 0); + } +} + +void +PTFFormat::parseblocks(void) { + uint32_t i = 20; + + while (i < _len) { + struct block_t b; + if (parse_block_at(i, &b, NULL, 0)) { + blocks.push_back(b); + } + i += b.block_size ? b.block_size + 7 : 1; + } +} + +int +PTFFormat::parse(void) { + parseblocks(); +#ifdef DEBUG + dump(); +#endif + if (!parseheader()) + return -1; + setrates(); + if (_sessionrate < 44100 || _sessionrate > 192000) + return -2; + if (!parseaudio()) + return -3; + if (!parserest()) + return -4; + if (!parsemidi()) + return -5; + return 0; +} + +bool +PTFFormat::parseheader(void) { + bool found = false; + + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x1028) { + _sessionrate = u_endian_read4(&_ptfunxored[b->offset+4], is_bigendian); + found = true; + } + } + return found; +} + +char * +PTFFormat::parsestring(uint32_t pos) { + uint32_t length = u_endian_read4(&_ptfunxored[pos], is_bigendian); + pos += 4; + return strndup((const char *)&_ptfunxored[pos], length); +} + +bool +PTFFormat::parseaudio(void) { + bool found = false; + uint32_t nwavs, i, n; + uint32_t pos = 0; + char *str; + std::string wavtype; + std::string wavname; + + // Parse wav names + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x1004) { + + nwavs = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian); + + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x103a) { + found = true; + //nstrings = u_endian_read4(&_ptfunxored[c->offset+1], is_bigendian); + pos = c->offset + 11; + // Found wav list + for (i = n = 0; (pos < c->offset + c->block_size) && (n < nwavs); i++) { + str = parsestring(pos); + wavname = std::string(str); + free(str); + pos += wavname.size() + 4; + str = strndup((const char *)&_ptfunxored[pos], 4); + wavtype = std::string(str); + free(str); + pos += 9; + if (foundin(wavname, std::string(".grp"))) + continue; + + if (foundin(wavname, std::string("Audio Files"))) { + continue; + } + if (foundin(wavname, std::string("Fade Files"))) { + continue; + } + if (_version < 10) { + if (!(foundin(wavtype, std::string("WAVE")) || + foundin(wavtype, std::string("EVAW")) || + foundin(wavtype, std::string("AIFF")) || + foundin(wavtype, std::string("FFIA"))) ) { + continue; + } + } else { + if (wavtype.size() != 0) { + if (!(foundin(wavtype, std::string("WAVE")) || + foundin(wavtype, std::string("EVAW")) || + foundin(wavtype, std::string("AIFF")) || + foundin(wavtype, std::string("FFIA"))) ) { + continue; + } + } else if (!(foundin(wavname, std::string(".wav")) || + foundin(wavname, std::string(".aif"))) ) { + continue; + } + } + wav_t f (n); + f.filename = wavname; + n++; + _audiofiles.push_back(f); + } + } + } + } + } + + // Add wav length information + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x1004) { + + vector::iterator wav = _audiofiles.begin(); + + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x1003) { + for (vector::iterator d = c->child.begin(); + d != c->child.end(); ++d) { + if (d->content_type == 0x1001) { + (*wav).length = u_endian_read8(&_ptfunxored[d->offset+8], is_bigendian); + wav++; + } + } + } + } + } + } + + return found; +} + + +void +PTFFormat::parse_three_point(uint32_t j, uint64_t& start, uint64_t& offset, uint64_t& length) { + uint8_t offsetbytes, lengthbytes, startbytes; + + if (is_bigendian) { + offsetbytes = (_ptfunxored[j+4] & 0xf0) >> 4; + lengthbytes = (_ptfunxored[j+3] & 0xf0) >> 4; + startbytes = (_ptfunxored[j+2] & 0xf0) >> 4; + //somethingbytes = (_ptfunxored[j+2] & 0xf); + //skipbytes = _ptfunxored[j+1]; + } else { + offsetbytes = (_ptfunxored[j+1] & 0xf0) >> 4; //3 + lengthbytes = (_ptfunxored[j+2] & 0xf0) >> 4; + startbytes = (_ptfunxored[j+3] & 0xf0) >> 4; //1 + //somethingbytes = (_ptfunxored[j+3] & 0xf); + //skipbytes = _ptfunxored[j+4]; + } + + switch (offsetbytes) { + case 5: + offset = u_endian_read5(&_ptfunxored[j+5], false); + break; + case 4: + offset = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false); + break; + case 3: + offset = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false); + break; + case 2: + offset = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false); + break; + case 1: + offset = (uint64_t)(_ptfunxored[j+5]); + break; + default: + offset = 0; + break; + } + j+=offsetbytes; + switch (lengthbytes) { + case 5: + length = u_endian_read5(&_ptfunxored[j+5], false); + break; + case 4: + length = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false); + break; + case 3: + length = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false); + break; + case 2: + length = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false); + break; + case 1: + length = (uint64_t)(_ptfunxored[j+5]); + break; + default: + length = 0; + break; + } + j+=lengthbytes; + switch (startbytes) { + case 5: + start = u_endian_read5(&_ptfunxored[j+5], false); + break; + case 4: + start = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false); + break; + case 3: + start = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false); + break; + case 2: + start = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false); + break; + case 1: + start = (uint64_t)(_ptfunxored[j+5]); + break; + default: + start = 0; + break; + } +} + +void +PTFFormat::parse_region_info(uint32_t j, block_t& blk, region_t& r) { + uint64_t findex, start, sampleoffset, length; + + parse_three_point(j, start, sampleoffset, length); + + findex = u_endian_read4(&_ptfunxored[blk.offset + blk.block_size], is_bigendian); + wav_t f (findex); + f.posabsolute = start * _ratefactor; + f.length = length * _ratefactor; + + wav_t found; + if (find_wav(findex, found)) { + f.filename = found.filename; + } + + std::vector m; + r.startpos = (int64_t)(start*_ratefactor); + r.sampleoffset = (int64_t)(sampleoffset*_ratefactor); + r.length = (int64_t)(length*_ratefactor); + r.wave = f; + r.midi = m; +} + +bool +PTFFormat::parserest(void) { + uint32_t i, j, count; + uint64_t start; + uint16_t rindex, rawindex, tindex, mindex; + uint32_t nch; + uint16_t ch_map[MAX_CHANNELS_PER_TRACK]; + bool found = false; + char *reg; + std::string regionname, trackname, midiregionname; + rindex = 0; + + // Parse sources->regions + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x100b || b->content_type == 0x262a) { + //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian); + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x1008 || c->content_type == 0x2629) { + vector::iterator d = c->child.begin(); + region_t r; + + found = true; + j = c->offset + 11; + reg = parsestring(j); + regionname = std::string(reg); + free(reg); + j += regionname.size() + 4; + + r.name = regionname; + r.index = rindex; + parse_region_info(j, *d, r); + + _regions.push_back(r); + rindex++; + } + } + found = true; + } + } + + // Parse tracks + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x1015) { + //ntracks = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian); + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x1014) { + j = c->offset + 2; + reg = parsestring(j); + trackname = std::string(reg); + j += trackname.size() + 5; + nch = u_endian_read4(&_ptfunxored[j], is_bigendian); + j += 4; + for (i = 0; i < nch; i++) { + ch_map[i] = u_endian_read2(&_ptfunxored[j], is_bigendian); + + track_t ti; + if (!find_track(ch_map[i], ti)) { + // Add a dummy region for now + region_t r (65535); + track_t t (ch_map[i]); + t.name = trackname; + t.reg = r; + _tracks.push_back(t); + } + //verbose_printf("%s : %d(%d)\n", reg, nch, ch_map[0]); + j += 2; + } + free(reg); + } + } + } + } + + // Reparse from scratch to exclude audio tracks from all tracks to get midi tracks + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x2519) { + tindex = 0; + mindex = 0; + //ntracks = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian); + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x251a) { + j = c->offset + 4; + reg = parsestring(j); + trackname = std::string(reg); + free(reg); + j += trackname.size() + 4 + 18; + //tindex = u_endian_read4(&_ptfunxored[j], is_bigendian); + + // Add a dummy region for now + region_t r (65535); + track_t t (mindex); + t.name = trackname; + t.reg = r; + + track_t ti; + // If the current track is not an audio track, insert as midi track + if (!(find_track(tindex, ti) && foundin(trackname, ti.name))) { + _miditracks.push_back(t); + mindex++; + } + tindex++; + } + } + } + } + + // Parse regions->tracks + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + tindex = 0; + if (b->content_type == 0x1012) { + //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian); + count = 0; + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x1011) { + reg = parsestring(c->offset + 2); + regionname = std::string(reg); + free(reg); + for (vector::iterator d = c->child.begin(); + d != c->child.end(); ++d) { + if (d->content_type == 0x100f) { + for (vector::iterator e = d->child.begin(); + e != d->child.end(); ++e) { + if (e->content_type == 0x100e) { + // Region->track + track_t ti; + j = e->offset + 4; + rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian); + if (!find_track(count, ti)) + continue; + if (!find_region(rawindex, ti.reg)) + continue; + if (ti.reg.index != 65535) { + _tracks.push_back(ti); + } + } + } + } + } + found = true; + count++; + } + } + } else if (b->content_type == 0x1054) { + //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian); + count = 0; + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x1052) { + reg = parsestring(c->offset + 2); + regionname = std::string(reg); + free(reg); + for (vector::iterator d = c->child.begin(); + d != c->child.end(); ++d) { + if (d->content_type == 0x1050) { + for (vector::iterator e = d->child.begin(); + e != d->child.end(); ++e) { + if (e->content_type == 0x104f) { + // Region->track + j = e->offset + 4; + rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian); + j += 4 + 1; + start = u_endian_read4(&_ptfunxored[j], is_bigendian); + tindex = count; + track_t ti; + if (!find_track(tindex, ti)) { + verbose_printf("dropped track %d\n", tindex); + continue; + } + if (!find_region(rawindex, ti.reg)) { + verbose_printf("dropped region %d\n", rawindex); + continue; + } + ti.reg.startpos = start; + if (ti.reg.index != 65535) { + _tracks.push_back(ti); + } + } + } + } + } + found = true; + count++; + } + } + } + } + for (std::vector::iterator tr = _tracks.begin(); + tr != _tracks.end(); /* noop */) { + if ((*tr).reg.index == 65535) { + tr = _tracks.erase(tr); + } else { + tr++; + } + } + return found; +} + +struct mchunk { + mchunk (uint64_t zt, uint64_t ml, std::vector const& c) + : zero (zt) + , maxlen (ml) + , chunk (c) + {} + uint64_t zero; + uint64_t maxlen; + std::vector chunk; +}; + +bool +PTFFormat::parsemidi(void) { + uint32_t i, j, k, n, rindex, tindex, mindex, count, rawindex; + uint64_t n_midi_events, zero_ticks, start, offset, length, start2, stop2; + uint64_t midi_pos, midi_len, max_pos, region_pos; + uint8_t midi_velocity, midi_note; + uint16_t regionnumber = 0; + std::string midiregionname; + + std::vector midichunks; + midi_ev_t m; + + char *str; + std::string regionname, trackname; + rindex = 0; + + // Parse MIDI events + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x2000) { + + k = b->offset; + + // Parse all midi chunks, not 1:1 mapping to regions yet + while (k + 35 < b->block_size + b->offset) { + max_pos = 0; + std::vector midi; + + if (!jumpto(&k, _ptfunxored, _len, (const unsigned char *)"MdNLB", 5)) { + break; + } + k += 11; + n_midi_events = u_endian_read4(&_ptfunxored[k], is_bigendian); + + k += 4; + zero_ticks = u_endian_read5(&_ptfunxored[k], is_bigendian); + for (i = 0; i < n_midi_events && k < _len; i++, k += 35) { + midi_pos = u_endian_read5(&_ptfunxored[k], is_bigendian); + midi_pos -= zero_ticks; + midi_note = _ptfunxored[k+8]; + midi_len = u_endian_read5(&_ptfunxored[k+9], is_bigendian); + midi_velocity = _ptfunxored[k+17]; + + if (midi_pos + midi_len > max_pos) { + max_pos = midi_pos + midi_len; + } + + m.pos = midi_pos; + m.length = midi_len; + m.note = midi_note; + m.velocity = midi_velocity; + midi.push_back(m); + } + midichunks.push_back(mchunk (zero_ticks, max_pos, midi)); + } + + // Put chunks onto regions + } else if ((b->content_type == 0x2002) || (b->content_type == 0x2634)) { + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if ((c->content_type == 0x2001) || (c->content_type == 0x2633)) { + for (vector::iterator d = c->child.begin(); + d != c->child.end(); ++d) { + if ((d->content_type == 0x1007) || (d->content_type == 0x2628)) { + j = d->offset + 2; + str = parsestring(j); + midiregionname = std::string(str); + j += 4 + midiregionname.size(); + parse_three_point(j, region_pos, zero_ticks, midi_len); + j = d->offset + d->block_size; + rindex = u_endian_read4(&_ptfunxored[j], is_bigendian); + struct mchunk mc = *(midichunks.begin()+rindex); + + region_t r (regionnumber++); + r.name = midiregionname; + r.startpos = (int64_t)0xe8d4a51000ULL; + r.sampleoffset = 0; + r.length = mc.maxlen; + r.midi = mc.chunk; + + _midiregions.push_back(r); + //verbose_printf("MIDI %s : r(%d) (%llu, %llu, %llu)\n", str, rindex, zero_ticks, region_pos, midi_len); + //dump_block(*d, 1); + free(str); + } + } + } + } + } + } + + // COMPOUND MIDI regions + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x262c) { + mindex = 0; + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x262b) { + for (vector::iterator d = c->child.begin(); + d != c->child.end(); ++d) { + if (d->content_type == 0x2628) { + count = 0; + j = d->offset + 2; + str = parsestring(j); + regionname = std::string(str); + j += 4 + regionname.size(); + parse_three_point(j, start, offset, length); + j = d->offset + d->block_size + 2; + n = u_endian_read2(&_ptfunxored[j], is_bigendian); + + for (vector::iterator e = d->child.begin(); + e != d->child.end(); ++e) { + if (e->content_type == 0x2523) { + // FIXME Compound MIDI region + j = e->offset + 39; + rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian); + j += 12; + start2 = u_endian_read5(&_ptfunxored[j], is_bigendian); + int64_t signedval = (int64_t)start2; + signedval -= ZERO_TICKS; + if (signedval < 0) { + signedval = -signedval; + } + start2 = signedval; + j += 8; + stop2 = u_endian_read5(&_ptfunxored[j], is_bigendian); + signedval = (int64_t)stop2; + signedval -= ZERO_TICKS; + if (signedval < 0) { + signedval = -signedval; + } + stop2 = signedval; + j += 16; + //nn = u_endian_read4(&_ptfunxored[j], is_bigendian); + //verbose_printf("COMPOUND %s : c(%d) r(%d) ?(%d) ?(%d) (%llu %llu)(%llu %llu %llu)\n", str, mindex, rawindex, n, nn, start2, stop2, start, offset, length); + count++; + } + } + if (!count) { + // Plain MIDI region + struct mchunk mc = *(midichunks.begin()+n); + + region_t r (n); + r.name = midiregionname; + r.startpos = (int64_t)0xe8d4a51000ULL; + r.length = mc.maxlen; + r.midi = mc.chunk; + _midiregions.push_back(r); + verbose_printf("%s : MIDI region mr(%d) ?(%d) (%llu %llu %llu)\n", str, mindex, n, start, offset, length); + mindex++; + } + free(str); + } + } + } + } + } + } + + // Put midi regions onto midi tracks + for (vector::iterator b = blocks.begin(); + b != blocks.end(); ++b) { + if (b->content_type == 0x1058) { + //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian); + count = 0; + for (vector::iterator c = b->child.begin(); + c != b->child.end(); ++c) { + if (c->content_type == 0x1057) { + str = parsestring(c->offset + 2); + regionname = std::string(str); + free(str); + for (vector::iterator d = c->child.begin(); + d != c->child.end(); ++d) { + if (d->content_type == 0x1056) { + for (vector::iterator e = d->child.begin(); + e != d->child.end(); ++e) { + if (e->content_type == 0x104f) { + // MIDI region->MIDI track + track_t ti; + j = e->offset + 4; + rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian); + j += 4 + 1; + start = u_endian_read5(&_ptfunxored[j], is_bigendian); + tindex = count; + if (!find_miditrack(tindex, ti)) { + verbose_printf("dropped midi t(%d) r(%d)\n", tindex, rawindex); + continue; + } + if (!find_midiregion(rawindex, ti.reg)) { + verbose_printf("dropped midiregion\n"); + continue; + } + //verbose_printf("MIDI : %s : t(%d) r(%d) %llu(%llu)\n", ti.name.c_str(), tindex, rawindex, start, ti.reg.startpos); + int64_t signedstart = (int64_t)(start - ZERO_TICKS); + if (signedstart < 0) + signedstart = -signedstart; + ti.reg.startpos = (uint64_t)signedstart; + if (ti.reg.index != 65535) { + _miditracks.push_back(ti); + } + } + } + } + } + count++; + } + } + } + } + for (std::vector::iterator tr = _miditracks.begin(); + tr != _miditracks.end(); /* noop */) { + if ((*tr).reg.index == 65535) { + tr = _miditracks.erase(tr); + } else { + tr++; + } + } + return true; +} diff --git a/libs/ptformat/ptformat/ptfformat.h b/libs/ptformat/ptformat/ptfformat.h deleted file mode 100644 index 72dc64c715..0000000000 --- a/libs/ptformat/ptformat/ptfformat.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * libptformat - a library to read ProTools sessions - * - * Copyright (C) 2015 Damien Zammit - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#ifndef PTFFORMAT_H -#define PTFFORMAT_H - -#include -#include -#include -#include -#include -#include "ptformat/visibility.h" - -class LIBPTFORMAT_API PTFFormat { -public: - PTFFormat(); - ~PTFFormat(); - - /* Return values: 0 success - -1 could not parse pt session - */ - int load(std::string path, int64_t targetsr); - - /* Return values: 0 success - -1 could not decrypt pt session - */ - int unxor(std::string path); - - struct wav_t { - std::string filename; - uint16_t index; - - int64_t posabsolute; - int64_t length; - - bool operator <(const struct wav_t& other) const { - return (strcasecmp(this->filename.c_str(), - other.filename.c_str()) < 0); - } - - bool operator ==(const struct wav_t& other) const { - return (this->filename == other.filename || - this->index == other.index); - } - - }; - - struct midi_ev_t { - uint64_t pos; - uint64_t length; - uint8_t note; - uint8_t velocity; - }; - - typedef struct region { - std::string name; - uint16_t index; - int64_t startpos; - int64_t sampleoffset; - int64_t length; - wav_t wave; - std::vector midi; - - bool operator ==(const struct region& other) { - return (this->index == other.index); - } - - bool operator <(const struct region& other) const { - return (strcasecmp(this->name.c_str(), - other.name.c_str()) < 0); - } - } region_t; - - typedef struct compound { - uint16_t curr_index; - uint16_t unknown1; - uint16_t level; - uint16_t ontopof_index; - uint16_t next_index; - std::string name; - } compound_t; - - typedef struct track { - std::string name; - uint16_t index; - uint8_t playlist; - region_t reg; - - bool operator ==(const struct track& other) { - return (this->name == other.name); - } - } track_t; - - std::vector audiofiles; - std::vector regions; - std::vector midiregions; - std::vector compounds; - std::vector tracks; - std::vector miditracks; - - static bool regionexistsin(std::vector reg, uint16_t index) { - std::vector::iterator begin = reg.begin(); - std::vector::iterator finish = reg.end(); - std::vector::iterator found; - - wav_t w = { std::string(""), 0, 0, 0 }; - std::vector m; - region_t r = { std::string(""), index, 0, 0, 0, w, m}; - - if ((found = std::find(begin, finish, r)) != finish) { - return true; - } - return false; - } - - static bool wavexistsin(std::vector wv, uint16_t index) { - std::vector::iterator begin = wv.begin(); - std::vector::iterator finish = wv.end(); - std::vector::iterator found; - - wav_t w = { std::string(""), index, 0, 0 }; - - if ((found = std::find(begin, finish, w)) != finish) { - return true; - } - return false; - } - - int64_t sessionrate; - int64_t targetrate; - uint8_t version; - uint8_t *product; - std::string path; - - unsigned char c0; - unsigned char c1; - unsigned char *ptfunxored; - uint64_t len; - bool is_bigendian; - -private: - bool jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen); - bool jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen); - bool foundin(std::string haystack, std::string needle); - int64_t foundat(unsigned char *haystack, uint64_t n, const char *needle); - uint16_t u_endian_read2(unsigned char *buf, bool); - uint32_t u_endian_read3(unsigned char *buf, bool); - uint32_t u_endian_read4(unsigned char *buf, bool); - uint64_t u_endian_read5(unsigned char *buf, bool); - - int parse(void); - bool parse_version(); - uint8_t gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative); - void setrates(void); - void cleanup(void); - void parse5header(void); - void parse7header(void); - void parse8header(void); - void parse9header(void); - void parse10header(void); - void parserest5(void); - void parserest89(void); - void parserest12(void); - void parseaudio5(void); - void parseaudio(void); - void parsemidi(void); - void parsemidi12(void); - void resort(std::vector& ws); - void resort(std::vector& rs); - void filter(std::vector& rs); - std::vector actualwavs; - float ratefactor; - std::string extension; - uint32_t upto; -}; - - -#endif diff --git a/libs/ptformat/ptformat/ptformat.h b/libs/ptformat/ptformat/ptformat.h new file mode 100644 index 0000000000..43b4dc1fbe --- /dev/null +++ b/libs/ptformat/ptformat/ptformat.h @@ -0,0 +1,282 @@ +/* + * libptformat - a library to read ProTools sessions + * + * Copyright (C) 2015-2019 Damien Zammit + * Copyright (C) 2015-2019 Robin Gareus + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef PTFFORMAT_H +#define PTFFORMAT_H + +#include +#include +#include +#include +#include +#include "ptformat/visibility.h" + +class LIBPTFORMAT_API PTFFormat { +public: + PTFFormat(); + ~PTFFormat(); + + /* Return values: 0 success + -1 error decrypting pt session + -2 error detecting pt session + -3 incompatible pt version + -4 error parsing pt session + */ + int load(std::string const& path, int64_t targetsr); + + /* Return values: 0 success + -1 error decrypting pt session + */ + int unxor(std::string const& path); + + struct wav_t { + std::string filename; + uint16_t index; + + int64_t posabsolute; + int64_t length; + + bool operator <(const struct wav_t& other) const { + return (strcasecmp(this->filename.c_str(), + other.filename.c_str()) < 0); + } + + bool operator ==(const struct wav_t& other) const { + return (this->filename == other.filename || + this->index == other.index); + } + + wav_t (uint16_t idx = 0) : index (idx), posabsolute (0), length (0) {} + }; + + struct midi_ev_t { + uint64_t pos; + uint64_t length; + uint8_t note; + uint8_t velocity; + midi_ev_t () : pos (0), length (0), note (0), velocity (0) {} + }; + + struct region_t { + std::string name; + uint16_t index; + int64_t startpos; + int64_t sampleoffset; + int64_t length; + wav_t wave; + std::vector midi; + + bool operator ==(const region_t& other) const { + return (this->index == other.index); + } + + bool operator <(const region_t& other) const { + return (strcasecmp(this->name.c_str(), + other.name.c_str()) < 0); + } + region_t (uint16_t idx = 0) : index (idx), startpos (0), sampleoffset (0), length (0) {} + }; + + struct track_t { + std::string name; + uint16_t index; + uint8_t playlist; + region_t reg; + + bool operator <(const track_t& other) const { + return (this->index < other.index); + } + + bool operator ==(const track_t& other) const { + return (this->index == other.index); + } + track_t (uint16_t idx = 0) : index (idx), playlist (0) {} + }; + + bool find_track(uint16_t index, track_t& tt) const { + std::vector::const_iterator begin = _tracks.begin(); + std::vector::const_iterator finish = _tracks.end(); + std::vector::const_iterator found; + + track_t t (index); + + if ((found = std::find(begin, finish, t)) != finish) { + tt = *found; + return true; + } + return false; + } + + bool find_region(uint16_t index, region_t& rr) const { + std::vector::const_iterator begin = _regions.begin(); + std::vector::const_iterator finish = _regions.end(); + std::vector::const_iterator found; + + region_t r; + r.index = index; + + if ((found = std::find(begin, finish, r)) != finish) { + rr = *found; + return true; + } + return false; + } + + bool find_miditrack(uint16_t index, track_t& tt) const { + std::vector::const_iterator begin = _miditracks.begin(); + std::vector::const_iterator finish = _miditracks.end(); + std::vector::const_iterator found; + + track_t t (index); + + if ((found = std::find(begin, finish, t)) != finish) { + tt = *found; + return true; + } + return false; + } + + bool find_midiregion(uint16_t index, region_t& rr) const { + std::vector::const_iterator begin = _midiregions.begin(); + std::vector::const_iterator finish = _midiregions.end(); + std::vector::const_iterator found; + + region_t r (index); + + if ((found = std::find(begin, finish, r)) != finish) { + rr = *found; + return true; + } + return false; + } + + bool find_wav(uint16_t index, wav_t& ww) const { + std::vector::const_iterator begin = _audiofiles.begin(); + std::vector::const_iterator finish = _audiofiles.end(); + std::vector::const_iterator found; + + wav_t w (index); + + if ((found = std::find(begin, finish, w)) != finish) { + ww = *found; + return true; + } + return false; + } + + static bool regionexistsin(std::vector const& reg, uint16_t index) { + std::vector::const_iterator begin = reg.begin(); + std::vector::const_iterator finish = reg.end(); + + region_t r (index); + + if (std::find(begin, finish, r) != finish) { + return true; + } + return false; + } + + static bool wavexistsin (std::vector const& wv, uint16_t index) { + std::vector::const_iterator begin = wv.begin(); + std::vector::const_iterator finish = wv.end(); + + wav_t w (index); + + if (std::find(begin, finish, w) != finish) { + return true; + } + return false; + } + + uint8_t version () const { return _version; } + int64_t sessionrate () const { return _sessionrate ; } + const std::string& path () { return _path; } + + const std::vector& audiofiles () const { return _audiofiles ; } + const std::vector& regions () const { return _regions ; } + const std::vector& midiregions () const { return _midiregions ; } + const std::vector& tracks () const { return _tracks ; } + const std::vector& miditracks () const { return _miditracks ; } + + const unsigned char* unxored_data () const { return _ptfunxored; } + uint64_t unxored_size () const { return _len; } + +private: + + std::vector _audiofiles; + std::vector _regions; + std::vector _midiregions; + std::vector _tracks; + std::vector _miditracks; + + std::string _path; + + unsigned char* _ptfunxored; + uint64_t _len; + int64_t _sessionrate; + uint8_t _version; + uint8_t* _product; + int64_t _targetrate; + float _ratefactor; + bool is_bigendian; + + struct block_t { + uint8_t zmark; // 'Z' + uint16_t block_type; // type of block + uint32_t block_size; // size of block + uint16_t content_type; // type of content + uint32_t offset; // offset in file + std::vector child; // vector of child blocks + }; + std::vector blocks; + + bool jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen); + bool jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen); + bool foundin(std::string const& haystack, std::string const& needle); + int64_t foundat(unsigned char *haystack, uint64_t n, const char *needle); + uint16_t u_endian_read2(unsigned char *buf, bool); + uint32_t u_endian_read3(unsigned char *buf, bool); + uint32_t u_endian_read4(unsigned char *buf, bool); + uint64_t u_endian_read5(unsigned char *buf, bool); + uint64_t u_endian_read8(unsigned char *buf, bool); + + char *parsestring(uint32_t pos); + const std::string get_content_description(uint16_t ctype); + int parse(void); + void parseblocks(void); + bool parseheader(void); + bool parserest(void); + bool parseaudio(void); + bool parsemidi(void); + void dump(void); + bool parse_block_at(uint32_t pos, struct block_t *b, struct block_t *parent, int level); + void dump_block(struct block_t& b, int level); + bool parse_version(); + void parse_region_info(uint32_t j, block_t& blk, region_t& r); + void parse_three_point(uint32_t j, uint64_t& start, uint64_t& offset, uint64_t& length); + uint8_t gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative); + void setrates(void); + void cleanup(void); + void free_block(struct block_t& b); + void free_all_blocks(void); +}; + +#endif diff --git a/libs/ptformat/wscript b/libs/ptformat/wscript index b638e92558..0b26ade2fb 100644 --- a/libs/ptformat/wscript +++ b/libs/ptformat/wscript @@ -30,10 +30,10 @@ def configure(conf): def build(bld): # Library if bld.is_defined ('INTERNAL_SHARED_LIBS'): - obj = bld.shlib (features = 'cxx cxxshlib', source = [ 'ptfformat.cc' ]) + obj = bld.shlib (features = 'cxx cxxshlib', source = [ 'ptformat.cc' ]) obj.defines = [ 'LIBPTFORMAT_DLL_EXPORTS=1' ] else: - obj = bld.stdlib (source = [ 'ptfformat.cc' ]) + obj = bld.stdlib (source = [ 'ptformat.cc' ]) obj.cxxflags = [ bld.env['compiler_flags_dict']['pic'] ] obj.cflags = [ bld.env['compiler_flags_dict']['pic'] ] -- cgit v1.2.3