302 lines
6.8 KiB
C++
302 lines
6.8 KiB
C++
//
|
|
// Programmer: Craig Stuart Sapp <craig@ccrma.stanford.edu>
|
|
// Creation Date: Wed Jan 13 08:31:19 PST 1999
|
|
// Last Modified: Mon Feb 9 21:26:32 PST 2015 Updated for C++11.
|
|
// Filename: tools/vlv.cpp
|
|
// URL: https://github.com/craigsapp/midifile/blob/master/tools/vlv.cpp
|
|
// Syntax: C++11
|
|
// vim: ts=3
|
|
//
|
|
// Description: Converts Variable Length Values into integers as
|
|
// well as converts integers into VLVs.
|
|
//
|
|
|
|
#include "Options.h"
|
|
|
|
#include <cstdlib>
|
|
#include <iomanip>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
using namespace std;
|
|
using namespace smf;
|
|
|
|
#define DECODE 0
|
|
#define ENCODE 1
|
|
|
|
|
|
void checkOptions (Options& opts);
|
|
void displayVLV (int number, ostream& out);
|
|
void example (void);
|
|
void printBinary (int number, ostream& out);
|
|
void usage (const string& command);
|
|
|
|
// User interface variables:
|
|
Options options; // for command-line processing
|
|
int Direction = DECODE; // decoding=0, encoding=1
|
|
int InputStyle = 16; // number base of the input (2, 10, or 16)
|
|
int OutputStyle = 16; // number base of the output (2, 10, or 16)
|
|
vector<int> Input; // storage of input numbers
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
int main(int argc, char** argv) {
|
|
options.setOptions(argc, argv);
|
|
checkOptions(options);
|
|
|
|
if (Direction == DECODE) { // decoding
|
|
unsigned long output = 0;
|
|
for (int i=0; i<(int)Input.size(); i++) {
|
|
output = output << 7;
|
|
output |= Input[i] & 0x7f;
|
|
}
|
|
|
|
switch (OutputStyle) {
|
|
case 2:
|
|
printBinary(output, cout);
|
|
cout << endl;
|
|
break;
|
|
case 16:
|
|
if (output < 16) {
|
|
cout << '0';
|
|
}
|
|
cout << hex << output << endl;
|
|
break;
|
|
default:
|
|
cout << dec << output << endl;
|
|
}
|
|
|
|
} else { // encoding
|
|
displayVLV(Input[0], cout);
|
|
cout << endl;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////
|
|
//
|
|
// checkOptions --
|
|
//
|
|
|
|
void checkOptions(Options& opts) {
|
|
opts.define("b|2|bin|binary=b", "input is binary");
|
|
opts.define("d|10|dec|decimal=b", "input is decimal");
|
|
opts.define("B=b", "print binary output");
|
|
opts.define("D=b", "print decimal output");
|
|
opts.define("author=b", "author of the program");
|
|
opts.define("version=b", "version of the program");
|
|
opts.define("example=b", "example usage of the program");
|
|
opts.define("h|help=b", "list of options for the program");
|
|
opts.process();
|
|
|
|
if (opts.getBoolean("author")) {
|
|
cout << "Written by Craig Stuart Sapp, "
|
|
<< "craig@ccrma.stanford.edu, January 1999" << endl;
|
|
exit(0);
|
|
} else if (opts.getBoolean("version")) {
|
|
cout << "vlv, version 2.0 (9 Feb 2015)\n"
|
|
<< "compiled: " << __DATE__ << endl;
|
|
exit(0);
|
|
} else if (opts.getBoolean("help")) {
|
|
usage(opts.getCommand());
|
|
exit(0);
|
|
} else if (opts.getBoolean("example")) {
|
|
example();
|
|
exit(0);
|
|
}
|
|
|
|
// determine input style (the default is hexadecimal)
|
|
if (opts.getBoolean("binary")) {
|
|
InputStyle = 2;
|
|
} else if (opts.getBoolean("decimal")) {
|
|
InputStyle = 10;
|
|
} else {
|
|
InputStyle = 16;
|
|
}
|
|
|
|
// determine output style (the default is hexadecimal)
|
|
if (opts.getBoolean("B")) {
|
|
OutputStyle = 2;
|
|
} else if (opts.getBoolean("D")) {
|
|
OutputStyle = 10;
|
|
} else {
|
|
OutputStyle = 16;
|
|
}
|
|
|
|
if (opts.getArgCount() == 0) {
|
|
usage(opts.getCommand());
|
|
exit(1);
|
|
} else if (opts.getArgCount() == 1) { // encoding into VLV values
|
|
Direction = ENCODE;
|
|
} else { // decoding from VLV values
|
|
Direction = DECODE;
|
|
}
|
|
|
|
// process the input numbers:
|
|
int inCount = opts.getArgCount();
|
|
if (inCount > 4) {
|
|
cout << "Error: VLV values cannot have more than four bytes" << endl;
|
|
exit(1);
|
|
}
|
|
|
|
Input.reserve(opts.getArgCount());
|
|
Input.resize(0);
|
|
|
|
for (int i=1; i<=opts.getArgCount(); i++) {
|
|
Input.push_back(strtol(opts.getArg(i).c_str(), NULL, InputStyle));
|
|
|
|
if (Direction == DECODE && i != inCount) {
|
|
if (Input.back() < 0x80 || Input.back() > 255) {
|
|
cout << "Invalid VLV byte: " << opts.getArg(i) << endl;
|
|
exit(1);
|
|
}
|
|
} else if (Direction == DECODE && i == inCount) {
|
|
if (Input.back() < 0 || Input.back() >0x7f) {
|
|
cout << "Invalid VLV byte: " << opts.getArg(i) << endl;
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////
|
|
//
|
|
// displayVLV -- prints the number in VLV form
|
|
//
|
|
|
|
void displayVLV(int number, ostream& out) {
|
|
unsigned long value = (unsigned long)number;
|
|
|
|
if (value >= (1 << 28)) {
|
|
cout << "Error: number too large to handle" << endl;
|
|
exit(1);
|
|
}
|
|
|
|
unsigned long byte[4];
|
|
byte[0] = (value >> 21) & 0x7f;
|
|
byte[1] = (value >> 14) & 0x7f;
|
|
byte[2] = (value >> 7) & 0x7f;
|
|
byte[3] = (value >> 0) & 0x7f;
|
|
|
|
int flag = 0;
|
|
for (int i=0; i<3; i++) {
|
|
if (byte[i] != 0) {
|
|
flag = 1;
|
|
}
|
|
if (flag) {
|
|
byte[i] |= 0x80;
|
|
}
|
|
}
|
|
|
|
for (int i=0; i<4; i++) {
|
|
if (byte[i] >= 0x80 || i == 3) {
|
|
switch (OutputStyle) {
|
|
case 2: printBinary(byte[i], out); break;
|
|
case 16:
|
|
if (byte[i] < 0x0f) {
|
|
out << '0';
|
|
}
|
|
out << hex << byte[i];
|
|
break;
|
|
default: out << dec << byte[i];
|
|
}
|
|
if (i != 3) {
|
|
cout << ' ';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////
|
|
//
|
|
// example -- shows various command-line option calls to program.
|
|
//
|
|
|
|
void example(void) {
|
|
cout <<
|
|
"\n"
|
|
"# convert a hex number to VLV bytes:\n"
|
|
"vlv 3fff\n"
|
|
"\n"
|
|
"# convert a hex number to VLV bytes in decimal notation:\n"
|
|
"vlv -D 3fff\n"
|
|
"\n"
|
|
"# convert a decimal number to VLV bytes in decimal notation:\n"
|
|
"vlv -d -D 54632\n"
|
|
"\n"
|
|
"# convert hex VLV bytes into hex number:\n"
|
|
"vlv 81 80 F4 00\n"
|
|
"\n"
|
|
"# convert hex VLV bytes into dec number:\n"
|
|
"vlv -D 81 80 F4 00\n"
|
|
"\n"
|
|
<< endl;
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////
|
|
//
|
|
// printBinary -- prints the number in binary form with no
|
|
// leading zeros.
|
|
//
|
|
|
|
void printBinary(int number, ostream& out) {
|
|
unsigned long value = (unsigned long) number;
|
|
int flag = 0;
|
|
|
|
for (int i=0; i<32; i++) {
|
|
if (value & (1 << (31-i))) {
|
|
flag = 1;
|
|
}
|
|
|
|
if (flag) {
|
|
if (value & (1 << (31-i))) {
|
|
out << '1';
|
|
} else {
|
|
out << '0';
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag == 0) {
|
|
out << '0';
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//////////////////////////////
|
|
//
|
|
// usage -- how to run this program from the command-line.
|
|
//
|
|
|
|
void usage(const string& command) {
|
|
cout <<
|
|
"\n"
|
|
"Convert/Create Variable Length Values.\n"
|
|
"\n"
|
|
"Usage: " << command << " [-d|-b] [-D|-B] number(s)\n"
|
|
"\n"
|
|
"Options:\n"
|
|
" -d = input numbers are given in decimal notation (hex is default)\n"
|
|
" -b = input numbers are given in binary notation (hex is default)\n"
|
|
" -D = output numbers are given in decimal notation (hex is default)\n"
|
|
" -B = output numbers are given in binary notation (hex is default)\n"
|
|
" --options = list all options, default values, and aliases\n"
|
|
"\n"
|
|
<< endl;
|
|
}
|
|
|
|
|
|
|