On Wed, April 2, 2008 2:36 am, Phil Dibowitz wrote:
> Stephen Warren wrote:
>> In congruity, I have some code to identify the action to take for a
>> specific EzHex/EZUp file, without relying on any facet of the filename.
>
> I'm curious as to what you use to figure it out... there are some tells
> like firmware has '<TYPE>Firmware_Main</TYPE>' ... but not all
> of them are so straight forward - did you just pick a unique option
> from each file?

Yes, pretty much. The algorithm will be the same as the current Python
code in congruity, with the addition of validating that there really is an
INFORMATION tag, and "IR learn" detection, which congruity didn't have.

I can post more details (e.g. a patch to just add the libconcord function)
when I'm back home and have access to the code, since that part is already
working, except for IR learn.

> Looks good to me. Obviously we'll have to read in the file significantly
> earlier inside of concordance. I don't think that's a problem, but
> exactly where is interesting. We could do it in parse_options *if* we
> happen to be in auto_mode (where we currently do the filename matching
> stuff), but then we have to know if we've read it in or not and read it
> in later as necessary. That's sub-optimal.

Yes, I hacked it in place of the file name munging code in concordance.c
for testing, but certainly wouldn't advocate checking that change in.

Your code flow suggestions sound good.

> In fact, we could even use the appropriate MODE_* defines as the
> filetype defines if we want (obviously we wouldn't use them all, just
> MODE_WRITE_* and MODE_LEARN_IR).

Well, we'd need to be careful that application operation mode definitions
don't creep into libconcord.h, so (from memory of the code) I imagine that
we'd end up with libconcord.h only defining the file types, and
concordance.c having a switch to map them.

> So as I've worked on the XS perl wrappers (finally got everything working
> tonight I think, now I'm just cleaning stuff up),

>From my limited knowledge of XS, I jokingly suggest it would have been
easier to port Python's ctypes module to Perl and use that instead, rather
than suffering XS:-) [Actually, all joking aside, I'm sure the Perl
community would love a ctypes module, but that's a whole other project].

> I've been thinking about the API, and I'm starting to think more and
> more that all our uint8_t* and uint32_t* stuff really should just be a
> void* blob which is internally a structure with the uint8_t* and the
> size inside of it. Not only do I think of that array as a opaque blob
> to the user, but I don't want our API/ABI to have to change when we
> make it into an mmap pointer or some other thing.

Well, on all platforms, mmap (or the equivalent) will always map the file
to some memory location, so we can always have a pointer and size. What is
different, is that we may need extra information to manage the mapping.

Equally, I do believe we want the client app to be able to access (read)
the raw file data (or parsed binary data etc.) directly, if for no other
reason than e.g. writing an app that uses libconcord to load/parse a file,
then the app can hexdump/disassemble/... the binary data, or something
like that.

So, what I would suggest is this:

APIs use a public structure:

struct Data {
  uint8_t *data;
  uint32_t data_size;
};

and we pass "Data*" to in-to/out-from APIs (no doubt we'd pick a better
name).

However, internally, we would allocate something like:

struct DataInternal {
  Data public;
  // Internal only information follow
#if defined(WIN32)
  HANDLE h; // or whatever, for Win32
#else
  int fd; // Unix mmap fd handle, or whatever
#endif
};

Then, our APIs work like this:

int func1(Data **data)
{
  DataInternal *dataint = (DataInternal *)malloc(sizeof(DataInternal));
  *data = (Data*)dataint;
  dataint->member = whatever;
  ...
}

int func2(Data *data)
{
  DataInternal *dataint = (DataInternal *)data;
  ...
}

This allows us to hide arbitrary hidden/internal information in the same
"handle" that the client app sees, whilst still allowing the app simple
access to what it might care about.

We can always expand DataInt (outside the Data part) to add new internal
information without breaking binary compatibility.

We can even expand Data by simply adding fields, although this will
obviously break client binary compatibility.

Alternatively, we could do this:

struct Data {
  uint8_t *data;
  uint32_t data_size;
  void *priv;
};

... and allocate a separate priv structure and point the public structure
at it. I like this a little less because:

a) We have to make 2 allocations
b) The client can see the priv member, which it doesn't care about.
c) The client could screw with the priv member, and point it somewhere else.

Actually, I'd also like to consider the case of an app that internally
creates an "EZHex" file in memory and passes this into libconcord. I guess
to support this, all we would need to add is an API like
create_Data_struct_from_memory_region, that remembers it doesn't need to
free the memory buffer, just the Data structure. Similarly, apps might
want to construct raw binary config-updates or firmware blobs, and pass
these into the write_*_to_remote functions. So, we shouldn't preclude
that. Perhaps the file IO functions should handle Data to allow for
mmaping in the future, but the remote interaction functions should either
still take in/size, *or* be documented to only use the public portions of
struct Data, so and app can create its own.


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to