mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-10 16:43:33 +02:00
Extensive changes to improve NoteTrack display and (some) editing, NoteTrack playback via MIDI, and Midi-to-Audio alignment.
This commit is contained in:
@@ -1,46 +1,147 @@
|
||||
README_MAC.txt for PortMidi
|
||||
Roger Dannenberg
|
||||
17 jan 2007
|
||||
20 nov 2009
|
||||
|
||||
To build PortMidi for Mac OS X:
|
||||
To build PortMidi for Mac OS X, you must install Xcode, and
|
||||
if you want to build from the command line, you should install
|
||||
CMake.
|
||||
|
||||
==== USING MAKE ====
|
||||
CMake can build either Makefiles or Xcode projects, or you
|
||||
can use the pre-built Xcode project. These approaches are
|
||||
described in separate sections below.
|
||||
|
||||
go back up to the portmidi
|
||||
directory and type
|
||||
==== CLEANING UP ====
|
||||
You can remove previously built apps, object code, and libraries by
|
||||
running "cd pm_mac; sh cleanslate.sh"
|
||||
|
||||
==== USING CMAKE (AND COMMAND LINE TOOLS) ====
|
||||
|
||||
Start in the portmedia/portmidi directory.
|
||||
|
||||
make -f pm_mac/Makefile.osx
|
||||
|
||||
(You can also copy pm_mac/Makefile.osx to Makfile in the
|
||||
portmidi directory and just type "make".)
|
||||
(Begin note: make will invoke cmake to build a Makefile and then make to
|
||||
build portmidi. This extra level allows you to correctly build
|
||||
both Release and Debug versions. Release is the default, so to get
|
||||
the Debug version, use:
|
||||
|
||||
The Makefile.osx will build all test programs and the portmidi
|
||||
library. You may want to modify the Makefile.osx to remove the
|
||||
PM_CHECK_ERRORS definition. For experimental software,
|
||||
especially programs running from the command line, we
|
||||
recommend using PM_CHECK_ERRORS -- it will terminate your
|
||||
program and print a helpful message if any PortMidi
|
||||
function returns an error code.
|
||||
make -f pm_mac/Makefile.osx configuration=Debug
|
||||
)
|
||||
|
||||
If you do not compile with PM_CHECK_ERRORS, you should
|
||||
check for errors yourself.
|
||||
Release version executables and libraries are now in
|
||||
portmedia/portmidi/Release
|
||||
|
||||
The make file will also build an OS X Universal (ppc and i386)
|
||||
dynamic link library using xcode. For instructions about this
|
||||
and other options, type
|
||||
Debug version executables and libraries are created in
|
||||
portmedia/portmidi/Debug
|
||||
The Debug versions are compiled with PM_CHECK_ERRORS which
|
||||
prints an error message and aborts when an error code is returned
|
||||
by PortMidi functions. This is useful for small command line
|
||||
applications. Otherwise, you should check and handle error returns
|
||||
in your program.
|
||||
|
||||
You can install portmidi as follows:
|
||||
|
||||
cd Release; sudo make install
|
||||
|
||||
This will install /usr/local/include/{portmidi.h, porttime.h}
|
||||
and /usr/local/lib/{libportmidi.dylib, libportmidi_s.a, libpmjni.dylib}
|
||||
|
||||
You should now make the pmdefaults.app:
|
||||
|
||||
make -f pm_mac/Makefile.osx pmdefaults
|
||||
|
||||
NOTES: xcode is likely to crash after building pmdefaults, but
|
||||
pmdefaults should be OK (it will be in Release)
|
||||
Once you get started, you can run make directly in the
|
||||
Debug or Release directories
|
||||
|
||||
make -f pm_mac/Makefile.osx help
|
||||
|
||||
==== USING XCODE ====
|
||||
|
||||
Open portmidi/pm_mac/pm_mac.xcode with Xcode and
|
||||
build what you need: if you are just exploring, start with
|
||||
the lib+test suite.
|
||||
(1) Open portmidi/portmidi.xcodeproj with Xcode and
|
||||
build what you need. The simplest thing is to build the
|
||||
ALL_BUILD target. The default will be to build the Debug
|
||||
version, but you may want to change this to Release.
|
||||
|
||||
The Debug version is compiled with PM_CHECK_ERRORS, and the
|
||||
Release version is not. PM_CHECK_ERRORS will print an error
|
||||
message and exit your program if any error is returned from
|
||||
a call into PortMidi.
|
||||
|
||||
CMake (currently) also creates MinSizRel and RelWithDebInfo
|
||||
versions, but only because I cannot figure out how to disable
|
||||
them.
|
||||
|
||||
You will probably want the application PmDefaults, which sets
|
||||
default MIDI In and Out devices for PortMidi. You may also
|
||||
want to build a Java application using PortMidi. Since I have
|
||||
not figured out how to use CMake to make an OS X Java application,
|
||||
use pm_mac/pm_mac.xcodeproj as follows:
|
||||
|
||||
(2) open pm_mac/pm_mac.xcodeproj
|
||||
|
||||
(3) pm_java/pmjni/portmidi_JportmidiApi.h is needed
|
||||
by libpmjni.jnilib, the Java native interface library. Since
|
||||
portmidi_JportmidiApi.h is included with PortMidi, you can skip
|
||||
to step 4, but if you really want to rebuild everything from
|
||||
scratch, build the JPortMidiHeaders project.
|
||||
|
||||
(4) If you did not build libpmjni.dylib using portmidi.xcodeproj,
|
||||
do it now. (It depends on portmidi_JportmidiApi.h, and the
|
||||
PmDefaults project depends on libpmjni.dylib.)
|
||||
|
||||
(5) Returning to pm_mac.xcodeproj, build the PmDefaults program.
|
||||
|
||||
(6) If you wish, copy pm_mac/build/Deployment/PmDefaults.app to
|
||||
your applications folder.
|
||||
|
||||
(7) If you want to install libportmidi.dylib, first make it with
|
||||
Xcode, then
|
||||
sudo make -f pm_mac/Makefile.osx install
|
||||
This command will install /usr/local/include/{porttime.h, portmidi.h}
|
||||
and /usr/local/lib/libportmidi.dylib
|
||||
Note that the "install" function of xcode creates portmidi/Release
|
||||
and does not install the library to /usr/local/lib, so please use
|
||||
the command line installer.
|
||||
|
||||
==== USING CMAKE TO BUILD Xcode PROJECT ====
|
||||
|
||||
(1) Install CMake if you do not have it already.
|
||||
|
||||
(2) Open portmedia/portmidi/CMakeLists.txt with CMake
|
||||
|
||||
(3) Use Configure and Generate buttons
|
||||
|
||||
(4) This creates portmedia/portmidi/portmidi.xcodeproj.
|
||||
|
||||
(5) Follow the directions above using Xcode to compile
|
||||
PortMidi.
|
||||
|
||||
Notes:
|
||||
(1) You will also use pm_mac/pm_mac.xcodeproj, which
|
||||
is not generated by CMake.
|
||||
(2) The portmidi.xcodeproj created by CMake will have absolute
|
||||
paths and depend on CMake, so it will not be very portable to other
|
||||
machines or even directories. You can cd to pm_mac and run
|
||||
clean_up_project.sh to convert pm_mac.xcodeproj to use relative
|
||||
paths and to remove the scripts that run CMake. You'll first have
|
||||
to modify pm_mac/clean_up_project.awk to contain the particular
|
||||
absolute path or your portmidi project. Also, this is a pretty simple
|
||||
and probably fragile hack to make a stand-alone xcode project. I
|
||||
don't recommend it. Instead, either use CMake all the time, or use
|
||||
the portmidi.xcodeproj you get with the distribution.
|
||||
|
||||
[pm_mac.xcodeproj courtesy of Leigh Smith]
|
||||
|
||||
CHANGELOG
|
||||
|
||||
20-Nov-2009 Roger B. Dannenberg
|
||||
Added some install instructions
|
||||
26-Sep-2009 Roger B. Dannenberg
|
||||
More changes for using CMake, Makefiles, XCode
|
||||
20-Sep-2009 Roger B. Dannenberg
|
||||
Modifications for using CMake
|
||||
14-Sep-2009 Roger B. Dannenberg
|
||||
Modifications for using CMake
|
||||
17-Jan-2007 Roger B. Dannenberg
|
||||
Explicit instructions for Xcode
|
||||
15-Jan-2007 Roger B. Dannenberg
|
||||
|
@@ -5,6 +5,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "portmidi.h"
|
||||
#include "pmutil.h"
|
||||
#include "pminternal.h"
|
||||
#include "pmmacosxcm.h"
|
||||
#include "readbinaryplist.h"
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -57,21 +57,29 @@
|
||||
#define MIDI_EOX 0xf7
|
||||
#define MIDI_STATUS_MASK 0x80
|
||||
|
||||
static MIDIClientRef client = NULL; /* Client handle to the MIDI server */
|
||||
static MIDIPortRef portIn = NULL; /* Input port handle */
|
||||
static MIDIPortRef portOut = NULL; /* Output port handle */
|
||||
// "Ref"s are pointers on 32-bit machines and ints on 64 bit machines
|
||||
// NULL_REF is our representation of either 0 or NULL
|
||||
#ifdef __LP64__
|
||||
#define NULL_REF 0
|
||||
#else
|
||||
#define NULL_REF NULL
|
||||
#endif
|
||||
|
||||
static MIDIClientRef client = NULL_REF; /* Client handle to the MIDI server */
|
||||
static MIDIPortRef portIn = NULL_REF; /* Input port handle */
|
||||
static MIDIPortRef portOut = NULL_REF; /* Output port handle */
|
||||
|
||||
extern pm_fns_node pm_macosx_in_dictionary;
|
||||
extern pm_fns_node pm_macosx_out_dictionary;
|
||||
|
||||
typedef struct midi_macosxcm_struct {
|
||||
unsigned long sync_time; /* when did we last determine delta? */
|
||||
PmTimestamp sync_time; /* when did we last determine delta? */
|
||||
UInt64 delta; /* difference between stream time and real time in ns */
|
||||
UInt64 last_time; /* last output time */
|
||||
int first_message; /* tells midi_write to sychronize timestamps */
|
||||
int sysex_mode; /* middle of sending sysex */
|
||||
unsigned long sysex_word; /* accumulate data when receiving sysex */
|
||||
unsigned int sysex_byte_count; /* count how many received */
|
||||
uint32_t sysex_word; /* accumulate data when receiving sysex */
|
||||
uint32_t sysex_byte_count; /* count how many received */
|
||||
char error[PM_HOST_ERROR_MSG_LEN];
|
||||
char callback_error[PM_HOST_ERROR_MSG_LEN];
|
||||
Byte packetBuffer[PACKET_BUFFER_SIZE];
|
||||
@@ -81,7 +89,7 @@ typedef struct midi_macosxcm_struct {
|
||||
MIDITimeStamp sysex_timestamp; /* timestamp to use with sysex data */
|
||||
/* allow for running status (is running status possible here? -rbd): -cpr */
|
||||
unsigned char last_command;
|
||||
long last_msg_length;
|
||||
int32_t last_msg_length;
|
||||
} midi_macosxcm_node, *midi_macosxcm_type;
|
||||
|
||||
/* private function declarations */
|
||||
@@ -92,7 +100,7 @@ char* cm_get_full_endpoint_name(MIDIEndpointRef endpoint);
|
||||
|
||||
|
||||
static int
|
||||
midi_length(long msg)
|
||||
midi_length(int32_t msg)
|
||||
{
|
||||
int status, high, low;
|
||||
static int high_lengths[] = {
|
||||
@@ -235,7 +243,7 @@ readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon)
|
||||
PmEvent event;
|
||||
MIDIPacket *packet;
|
||||
unsigned int packetIndex;
|
||||
unsigned long now;
|
||||
uint32_t now;
|
||||
unsigned int status;
|
||||
|
||||
#ifdef CM_DEBUG
|
||||
@@ -260,9 +268,9 @@ readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon)
|
||||
packet->length); */
|
||||
for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) {
|
||||
/* Set the timestamp and dispatch this message */
|
||||
event.timestamp =
|
||||
event.timestamp = (PmTimestamp) /* explicit conversion */ (
|
||||
(AudioConvertHostTimeToNanos(packet->timeStamp) - m->delta) /
|
||||
(UInt64) 1000000;
|
||||
(UInt64) 1000000);
|
||||
status = packet->data[0];
|
||||
/* process packet as sysex data if it begins with MIDI_SYSEX, or
|
||||
MIDI_EOX or non-status byte with no running status */
|
||||
@@ -303,9 +311,8 @@ midi_in_open(PmInternal *midi, void *driverInfo)
|
||||
/* time_get does not take a parameter, so coerce */
|
||||
midi->time_proc = (PmTimeProcPtr) Pt_Time;
|
||||
}
|
||||
|
||||
endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
|
||||
if (endpoint == NULL) {
|
||||
endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
|
||||
if (endpoint == NULL_REF) {
|
||||
return pmInvalidDeviceId;
|
||||
}
|
||||
|
||||
@@ -333,7 +340,7 @@ midi_in_open(PmInternal *midi, void *driverInfo)
|
||||
pm_hosterror = macHostError;
|
||||
sprintf(pm_hosterror_text,
|
||||
"Host error %ld: MIDIPortConnectSource() in midi_in_open()",
|
||||
macHostError);
|
||||
(long) macHostError);
|
||||
midi->descriptor = NULL;
|
||||
pm_free(m);
|
||||
return pmHostError;
|
||||
@@ -353,8 +360,8 @@ midi_in_close(PmInternal *midi)
|
||||
|
||||
if (!m) return pmBadPtr;
|
||||
|
||||
endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
|
||||
if (endpoint == NULL) {
|
||||
endpoint = (MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
|
||||
if (endpoint == NULL_REF) {
|
||||
pm_hosterror = pmBadPtr;
|
||||
}
|
||||
|
||||
@@ -364,7 +371,7 @@ midi_in_close(PmInternal *midi)
|
||||
pm_hosterror = macHostError;
|
||||
sprintf(pm_hosterror_text,
|
||||
"Host error %ld: MIDIPortDisconnectSource() in midi_in_close()",
|
||||
macHostError);
|
||||
(long) macHostError);
|
||||
err = pmHostError;
|
||||
}
|
||||
|
||||
@@ -421,12 +428,12 @@ midi_abort(PmInternal *midi)
|
||||
PmError err = pmNoError;
|
||||
OSStatus macHostError;
|
||||
MIDIEndpointRef endpoint =
|
||||
(MIDIEndpointRef) descriptors[midi->device_id].descriptor;
|
||||
(MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
|
||||
macHostError = MIDIFlushOutput(endpoint);
|
||||
if (macHostError != noErr) {
|
||||
pm_hosterror = macHostError;
|
||||
sprintf(pm_hosterror_text,
|
||||
"Host error %ld: MIDIFlushOutput()", macHostError);
|
||||
"Host error %ld: MIDIFlushOutput()", (long) macHostError);
|
||||
err = pmHostError;
|
||||
}
|
||||
return err;
|
||||
@@ -439,7 +446,7 @@ midi_write_flush(PmInternal *midi, PmTimestamp timestamp)
|
||||
OSStatus macHostError;
|
||||
midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
|
||||
MIDIEndpointRef endpoint =
|
||||
(MIDIEndpointRef) descriptors[midi->device_id].descriptor;
|
||||
(MIDIEndpointRef) (long) descriptors[midi->device_id].descriptor;
|
||||
assert(m);
|
||||
assert(endpoint);
|
||||
if (m->packet != NULL) {
|
||||
@@ -454,7 +461,7 @@ send_packet_error:
|
||||
pm_hosterror = macHostError;
|
||||
sprintf(pm_hosterror_text,
|
||||
"Host error %ld: MIDISend() in midi_write()",
|
||||
macHostError);
|
||||
(long) macHostError);
|
||||
return pmHostError;
|
||||
|
||||
}
|
||||
@@ -476,7 +483,12 @@ send_packet(PmInternal *midi, Byte *message, unsigned int messageLength,
|
||||
/* out of space, send the buffer and start refilling it */
|
||||
/* make midi->packet non-null to fool midi_write_flush into sending */
|
||||
m->packet = (MIDIPacket *) 4;
|
||||
if ((err = midi_write_flush(midi, timestamp)) != pmNoError) return err;
|
||||
/* timestamp is 0 because midi_write_flush ignores timestamp since
|
||||
* timestamps are already in packets. The timestamp parameter is here
|
||||
* because other API's need it. midi_write_flush can be called
|
||||
* from system-independent code that must be cross-API.
|
||||
*/
|
||||
if ((err = midi_write_flush(midi, 0)) != pmNoError) return err;
|
||||
m->packet = MIDIPacketListInit(m->packetList);
|
||||
assert(m->packet); /* if this fails, it's a programming error */
|
||||
m->packet = MIDIPacketListAdd(m->packetList, sizeof(m->packetBuffer),
|
||||
@@ -491,8 +503,8 @@ send_packet(PmInternal *midi, Byte *message, unsigned int messageLength,
|
||||
static PmError
|
||||
midi_write_short(PmInternal *midi, PmEvent *event)
|
||||
{
|
||||
long when = event->timestamp;
|
||||
long what = event->message;
|
||||
PmTimestamp when = event->timestamp;
|
||||
PmMessage what = event->message;
|
||||
MIDITimeStamp timestamp;
|
||||
UInt64 when_ns;
|
||||
midi_macosxcm_type m = (midi_macosxcm_type) midi->descriptor;
|
||||
@@ -659,9 +671,9 @@ CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
|
||||
CFRelease(str);
|
||||
}
|
||||
|
||||
MIDIEntityRef entity = NULL;
|
||||
MIDIEntityRef entity = NULL_REF;
|
||||
MIDIEndpointGetEntity(endpoint, &entity);
|
||||
if (entity == NULL)
|
||||
if (entity == NULL_REF)
|
||||
// probably virtual
|
||||
return result;
|
||||
|
||||
@@ -675,9 +687,9 @@ CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
|
||||
}
|
||||
}
|
||||
// now consider the device's name
|
||||
MIDIDeviceRef device = NULL;
|
||||
MIDIDeviceRef device = NULL_REF;
|
||||
MIDIEntityGetDevice(entity, &device);
|
||||
if (device == NULL)
|
||||
if (device == NULL_REF)
|
||||
return result;
|
||||
|
||||
str = NULL;
|
||||
@@ -722,17 +734,17 @@ static CFStringRef ConnectedEndpointName(MIDIEndpointRef endpoint)
|
||||
CFMutableStringRef result = CFStringCreateMutable(NULL, 0);
|
||||
CFStringRef str;
|
||||
OSStatus err;
|
||||
int i;
|
||||
long i;
|
||||
|
||||
// Does the endpoint have connections?
|
||||
CFDataRef connections = NULL;
|
||||
int nConnected = 0;
|
||||
long nConnected = 0;
|
||||
bool anyStrings = false;
|
||||
err = MIDIObjectGetDataProperty(endpoint, kMIDIPropertyConnectionUniqueID, &connections);
|
||||
if (connections != NULL) {
|
||||
// It has connections, follow them
|
||||
// Concatenate the names of all connected devices
|
||||
nConnected = CFDataGetLength(connections) / sizeof(MIDIUniqueID);
|
||||
nConnected = CFDataGetLength(connections) / (int32_t) sizeof(MIDIUniqueID);
|
||||
if (nConnected) {
|
||||
const SInt32 *pid = (const SInt32 *)(CFDataGetBytePtr(connections));
|
||||
for (i = 0; i < nConnected; ++i, ++pid) {
|
||||
@@ -901,7 +913,7 @@ PmError pm_macosxcm_init(void)
|
||||
/* Iterate over the MIDI input devices */
|
||||
for (i = 0; i < numInputs; i++) {
|
||||
endpoint = MIDIGetSource(i);
|
||||
if (endpoint == NULL) {
|
||||
if (endpoint == NULL_REF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -911,13 +923,13 @@ PmError pm_macosxcm_init(void)
|
||||
|
||||
/* Register this device with PortMidi */
|
||||
pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint),
|
||||
TRUE, (void*)endpoint, &pm_macosx_in_dictionary);
|
||||
TRUE, (void *) (long) endpoint, &pm_macosx_in_dictionary);
|
||||
}
|
||||
|
||||
/* Iterate over the MIDI output devices */
|
||||
for (i = 0; i < numOutputs; i++) {
|
||||
endpoint = MIDIGetDestination(i);
|
||||
if (endpoint == NULL) {
|
||||
if (endpoint == NULL_REF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -927,20 +939,22 @@ PmError pm_macosxcm_init(void)
|
||||
|
||||
/* Register this device with PortMidi */
|
||||
pm_add_device("CoreMIDI", cm_get_full_endpoint_name(endpoint),
|
||||
FALSE, (void*)endpoint, &pm_macosx_out_dictionary);
|
||||
FALSE, (void *) (long) endpoint,
|
||||
&pm_macosx_out_dictionary);
|
||||
}
|
||||
return pmNoError;
|
||||
|
||||
error_return:
|
||||
pm_hosterror = macHostError;
|
||||
sprintf(pm_hosterror_text, "Host error %ld: %s\n", macHostError, error_text);
|
||||
sprintf(pm_hosterror_text, "Host error %ld: %s\n", (long) macHostError,
|
||||
error_text);
|
||||
pm_macosxcm_term(); /* clear out any opened ports */
|
||||
return pmHostError;
|
||||
}
|
||||
|
||||
void pm_macosxcm_term(void)
|
||||
{
|
||||
if (client != NULL) MIDIClientDispose(client);
|
||||
if (portIn != NULL) MIDIPortDispose(portIn);
|
||||
if (portOut != NULL) MIDIPortDispose(portOut);
|
||||
if (client != NULL_REF) MIDIClientDispose(client);
|
||||
if (portIn != NULL_REF) MIDIPortDispose(portIn);
|
||||
if (portOut != NULL_REF) MIDIPortDispose(portOut);
|
||||
}
|
||||
|
@@ -3,6 +3,10 @@
|
||||
readbinaryplist.c -- Roger B. Dannenberg, Jun 2008
|
||||
Based on ReadBinaryPList.m by Jens Ayton, 2007
|
||||
|
||||
Note that this code is intended to read preference files and has an upper
|
||||
bound on file size (currently 100MB) and assumes in some places that 32 bit
|
||||
offsets are sufficient.
|
||||
|
||||
Here are his comments:
|
||||
|
||||
Reader for binary property list files (version 00).
|
||||
@@ -74,13 +78,25 @@ memory requested or calls longjmp, so callers don't have to check.
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include "readbinaryplist.h"
|
||||
#include <Carbon/Carbon.h>
|
||||
#define BPLIST_LOG_VERBOSE 1
|
||||
#include "Folders.h"
|
||||
|
||||
#define NO 0
|
||||
#define YES 1
|
||||
#define BOOL int
|
||||
|
||||
#define MAXPATHLEN 256
|
||||
|
||||
/* there are 2 levels of error logging/printing:
|
||||
* BPLIST_LOG and BPLIST_LOG_VERBOSE
|
||||
* either or both can be set to non-zero to turn on
|
||||
* If BPLIST_LOG_VERBOSE is true, then BPLIST_LOG
|
||||
* is also true.
|
||||
*
|
||||
* In the code, logging is done by calling either
|
||||
* bplist_log() or bplist_log_verbose(), which take
|
||||
* parameters like printf but might be a no-op.
|
||||
*/
|
||||
|
||||
/* #define BPLIST_LOG_VERBOSE 1 */
|
||||
|
||||
#if BPLIST_LOG_VERBOSE
|
||||
@@ -245,7 +261,7 @@ void value_set_uid(value_ptr v, uint64_t uid)
|
||||
v->tag = kTAG_UID; v->uinteger = uid;
|
||||
}
|
||||
|
||||
// value->data points to a pldata that points to the actual bytes
|
||||
// v->data points to a pldata that points to the actual bytes
|
||||
// the bytes are copied, so caller must free byte source (*data)
|
||||
void value_set_data(value_ptr v, const uint8_t *data, size_t len) {
|
||||
v->tag = kTAG_DATA;
|
||||
@@ -324,18 +340,26 @@ value_ptr bplist_read_file(char *filename)
|
||||
value_ptr value;
|
||||
int rslt = stat(filename, &stbuf);
|
||||
if (rslt) {
|
||||
perror("in stat: ");
|
||||
#if BPLIST_LOG
|
||||
perror("in stat");
|
||||
#endif
|
||||
bplist_log("Could not stat %s, error %d\n", filename, rslt);
|
||||
return NULL;
|
||||
}
|
||||
pldata.len = stbuf.st_size;
|
||||
// if file is >100MB, assume it is not a preferences file and give up
|
||||
if (stbuf.st_size > 100000000) {
|
||||
bplist_log("Large file %s encountered (%llu bytes) -- not read\n",
|
||||
filename, stbuf.st_size);
|
||||
return NULL;
|
||||
}
|
||||
pldata.len = (size_t) stbuf.st_size;
|
||||
// note: this is supposed to be malloc, not allocate. It is separate
|
||||
// from the graph structure, large, and easy to free right after
|
||||
// parsing.
|
||||
pldata.data = (uint8_t *) malloc(pldata.len);
|
||||
if (!pldata.data) {
|
||||
bplist_log("Could not allocate %d bytes for %s\n",
|
||||
(long) pldata.len, filename);
|
||||
bplist_log("Could not allocate %lu bytes for %s\n",
|
||||
(unsigned long) pldata.len, filename);
|
||||
return NULL;
|
||||
}
|
||||
file = fopen(filename, "rb");
|
||||
@@ -664,7 +688,8 @@ static value_ptr extract_real(bplist_info_ptr bplist, uint64_t offset)
|
||||
}
|
||||
|
||||
if (size == sizeof (float)) {
|
||||
uint32_t i = read_sized_int(bplist, offset + 1, size);
|
||||
// cast is ok because we know size is 4 bytes
|
||||
uint32_t i = (uint32_t) read_sized_int(bplist, offset + 1, size);
|
||||
// Note that this handles byte swapping.
|
||||
value_set_real(value, *(float *)&i);
|
||||
return value;
|
||||
@@ -755,7 +780,8 @@ static value_ptr extract_data(bplist_info_ptr bplist, uint64_t offset)
|
||||
return NULL;
|
||||
|
||||
value = value_create();
|
||||
value_set_data(value, bplist->data_bytes + offset, size);
|
||||
// cast is ok because we only allow files up to 100MB:
|
||||
value_set_data(value, bplist->data_bytes + (size_t) offset, (size_t) size);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -772,7 +798,9 @@ static value_ptr extract_ascii_string(bplist_info_ptr bplist, uint64_t offset)
|
||||
return NULL;
|
||||
|
||||
value = value_create();
|
||||
value_set_ascii_string(value, bplist->data_bytes + offset, size);
|
||||
// cast is ok because we only allow 100MB files
|
||||
value_set_ascii_string(value, bplist->data_bytes + (size_t) offset,
|
||||
(size_t) size);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -789,7 +817,9 @@ static value_ptr extract_unicode_string(bplist_info_ptr bplist, uint64_t offset)
|
||||
return NULL;
|
||||
|
||||
value = value_create();
|
||||
value_set_unicode_string(value, bplist->data_bytes + offset, size);
|
||||
// cast is ok because we only allow 100MB files
|
||||
value_set_unicode_string(value, bplist->data_bytes + (size_t) offset,
|
||||
(size_t) size);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -814,15 +844,20 @@ static value_ptr extract_uid(bplist_info_ptr bplist, uint64_t offset)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(NO); // original code suggests using a string for a key
|
||||
// assert(NO); // original code suggests using a string for a key
|
||||
// but our dictionaries all use big ints for keys, so I don't know
|
||||
// what to do here
|
||||
|
||||
// In practice, I believe this code is never executed by PortMidi.
|
||||
// I changed it to do something and not raise compiler warnings, but
|
||||
// not sure what the code should do.
|
||||
|
||||
value = value_create();
|
||||
value_set_uid(value, uid);
|
||||
// return [NSDictionary dictionaryWithObject:
|
||||
// [NSNumber numberWithUnsignedLongLong:value]
|
||||
// forKey:"CF$UID"];
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -861,11 +896,12 @@ static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset)
|
||||
assert(value);
|
||||
|
||||
if (count == 0) {
|
||||
value_set_array(value, array, count);
|
||||
// count must be size_t or smaller because max file size is 100MB
|
||||
value_set_array(value, array, (size_t) count);
|
||||
return value;
|
||||
}
|
||||
|
||||
array = allocate(sizeof(value_ptr) * count);
|
||||
array = allocate(sizeof(value_ptr) * (size_t) count);
|
||||
|
||||
for (i = 0; i != count; ++i) {
|
||||
bplist_log_verbose("[%u]\n", i);
|
||||
@@ -879,8 +915,8 @@ static value_ptr extract_array(bplist_info_ptr bplist, uint64_t offset)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
value_set_array(value, array, count);
|
||||
if (ok) { // count is smaller than size_t max because of 100MB file limit
|
||||
value_set_array(value, array, (size_t) count);
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@@ -3,6 +3,8 @@
|
||||
Roger B. Dannenberg, Jun 2008
|
||||
*/
|
||||
|
||||
#include <stdint.h> /* for uint8_t ... */
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
@@ -34,13 +36,13 @@ enum
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct pldata_struct {
|
||||
uint8_t *data;
|
||||
size_t len;
|
||||
} pldata_node, *pldata_ptr;
|
||||
|
||||
|
||||
typedef struct {
|
||||
typedef struct array_struct {
|
||||
struct value_struct **array;
|
||||
uint64_t length;
|
||||
} array_node, *array_ptr;
|
||||
|
Reference in New Issue
Block a user