"Fossies" - the Fresh Open Source Software Archive

Member "libgphoto2-2.5.27/camlibs/ptp2/olympus-wrap.c" (14 Feb 2021, 40724 Bytes) of package /linux/privat/libgphoto2-2.5.27.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "olympus-wrap.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.5.26_vs_2.5.27.

    1 /* olympus_wrap.c
    2  *
    3  * Copyright (c) 2012-2013 Marcus Meissner  <marcus@jet.franken.de>
    4  *
    5  * This library is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU Lesser General Public
    7  * License as published by the Free Software Foundation; either
    8  * version 2.1 of the License, or (at your option) any later version.
    9  *
   10  * This library is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13  * Lesser General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU Lesser General Public
   16  * License along with this library; if not, write to the
   17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   18  * Boston, MA  02110-1301  USA
   19  *
   20  * Notes:
   21  * XDISCVRY.X3C file sent on start, empty.
   22  */
   23 
   24 #define _DEFAULT_SOURCE
   25 
   26 #include "config.h"
   27 
   28 #ifdef HAVE_LIBXML2
   29 
   30 #include <string.h>
   31 #include <stdlib.h>
   32 #include <stdio.h>
   33 #include <_stdint.h>
   34 
   35 #include <libxml/parser.h>
   36 
   37 #include "ptp.h"
   38 #include "ptp-private.h"
   39 #include "ptp-pack.c"
   40 #include "olympus-wrap.h"
   41 
   42 #include <gphoto2/gphoto2-library.h>
   43 #include <gphoto2/gphoto2-setting.h>
   44 #include <gphoto2/gphoto2-result.h>
   45 #include <gphoto2/gphoto2-port-log.h>
   46 
   47 /*
   48  * The following things are the way the are just to ensure that USB
   49  * wrapper packets have the correct byte-order on all types of machines.
   50  * Intel byte order is used instead of "network" byte order :-(
   51  */
   52 typedef struct
   53 { unsigned char c1, c2, c3, c4; } uw32_t; /* A type for 32-bit integers */
   54 typedef struct
   55 { unsigned char c1, c2, c3, c4; } uw4c_t; /* A type for 4-byte things */
   56 
   57 static uw32_t uw_value(unsigned int value) /* Convert from host-integer to uw32_t */
   58 {
   59    uw32_t ret;
   60    ret.c1 = (value       & 0x000000ffUL);
   61    ret.c2 = (value >> 8  & 0x000000ffUL);
   62    ret.c3 = (value >> 16 & 0x000000ffUL);
   63    ret.c4 = (value >> 24 & 0x000000ffUL);
   64    return ret;
   65 }
   66 
   67 static unsigned char
   68 cmdbyte (unsigned char nr) {
   69     return nr | 0xc0;
   70 }
   71 
   72 /* Test for equality between two uw32_t's or two uw4c_t's. */
   73 #define UW_EQUAL(a, b) \
   74 ((a).c1==(b).c1 && (a).c2==(b).c2 && (a).c3==(b).c3 && (a).c4==(b).c4)
   75 
   76 /*
   77  * USB storage wrapper packets start with ASCII bytes "USBC".
   78  * The responses back from the camera start with "USBS".
   79  */
   80 #define UW_MAGIC_OUT ((uw4c_t){ 'U','S','B','C' })
   81 #define UW_MAGIC_IN  ((uw4c_t){ 'U','S','B','S' })
   82 
   83 #pragma pack(1)
   84 /*
   85  * The rest of the USB wrapper packet looks like this:
   86  */
   87 
   88 /* This is linux/include/linux/usb/storage.h, struct bulk_cb_wrap
   89  * 31 byte length */
   90 typedef struct
   91 {
   92       uw4c_t magic;     /* The letters U S B C for packets sent to camera */
   93       uw32_t tag;       /* The SCSI command tag */
   94       uw32_t rw_length;     /* Length of data to be read or written next */
   95       unsigned char flags;  /* in / out flag mostly */
   96       unsigned char lun;    /* 0 here */
   97       unsigned char length; /* of the CDB... but 0x0c is used here in the traces */
   98       unsigned char cdb[16];
   99 } uw_header_t;
  100 
  101 /*
  102  * This is the end response block from the camera looks like this:
  103  *
  104  * This is the generic bulk style USB Storage response block.
  105  *
  106  * linux/include/linux/usb/storage.h, struct bulk_cs_wrap */
  107 typedef struct
  108 {
  109       uw4c_t magic; /* The letters U S B S for packets from camera */
  110       uw32_t tag;   /* A copy of whatever value the host made up */
  111       uw32_t residue;   /* residual read? */
  112       char   status;    /* status byte */
  113 } uw_response_t;
  114 
  115 
  116 /* In the SCSI API, the CDB[16] block. */
  117 typedef struct
  118 {
  119       unsigned char cmd;
  120       char   zero1[8];
  121       uw32_t length;
  122       char   zero2[3];
  123 } uw_scsicmd_t;
  124 
  125 #pragma pack()
  126 
  127 /* This is for the unique tag id for the UMS command / response
  128  * It gets incremented by one for every command.
  129  */
  130 static int ums_tag = 0x42424242;
  131 /*
  132  * This routine is called after every UW_REQUEST_XXX to get an OK
  133  * with a matching session ID.
  134  */
  135 static int
  136 usb_wrap_OK (GPPort *dev, uw_header_t *hdr)
  137 {
  138     uw_response_t rsp;
  139     int ret;
  140     memset(&rsp, 0, sizeof(rsp));
  141 
  142     GP_LOG_D ("usb_wrap_OK");
  143     if ((ret = gp_port_read(dev, (char*)&rsp, sizeof(rsp))) != sizeof(rsp)) {
  144         GP_LOG_D ("gp_port_read *** FAILED (%d vs %d bytes)", (int)sizeof(rsp), ret);
  145         if (ret < GP_OK)
  146             return ret;
  147         return GP_ERROR;
  148     }
  149     if (    !UW_EQUAL(rsp.magic, UW_MAGIC_IN) ||
  150         !UW_EQUAL(rsp.tag, hdr->tag))
  151     {
  152         GP_LOG_E ("usb_wrap_OK wrong session *** FAILED");
  153         return GP_ERROR;
  154     }
  155     /*
  156      * 32bit residual length (0) and 8 bit status (0) are good.
  157      */
  158     if (    rsp.residue.c1 != 0 ||
  159         rsp.residue.c2 != 0 ||
  160         rsp.residue.c3 != 0 ||
  161         rsp.residue.c4 != 0 ||
  162         rsp.status != 0) {
  163         GP_LOG_E ("Error: usb_wrap_OK failed - residual non-0 or status %x", rsp.status);
  164         return GP_ERROR;
  165     }
  166     return GP_OK;
  167 }
  168 
  169 /* so it mirrors:
  170     ret = gp_port_send_scsi_cmd (camera->port, 1, (char*)&cmd, sizeof(cmd),
  171         sense_buffer, sizeof(sense_buffer), (char*)&usbreq, usbreq.length);
  172  */
  173 static int
  174 scsi_wrap_cmd(
  175     GPPort *port,
  176     int todev,
  177     char *cmd,   unsigned int cmdlen,
  178     char *sense, unsigned int senselen,
  179     char *data,  unsigned int size
  180 ) {
  181     uw_header_t     hdr;
  182     int         ret;
  183 
  184     memset(&hdr, 0, sizeof(hdr));
  185     hdr.magic   = UW_MAGIC_OUT;
  186     hdr.tag     = uw_value(ums_tag);
  187     ums_tag++;
  188     hdr.rw_length   = uw_value(size);
  189     hdr.length  = 12; /* seems to be always 12, even as we send 16 byte CDBs */
  190     hdr.flags   = todev?0:(1<<7);
  191     hdr.lun     = 0;
  192 
  193     memcpy(hdr.cdb, cmd, cmdlen);
  194 
  195     if ((ret=gp_port_write(port, (char*)&hdr, sizeof(hdr))) < GP_OK) {
  196         GP_LOG_E ("scsi_wrap_cmd *** FAILED to write scsi cmd");
  197         return GP_ERROR_IO;
  198     }
  199     if (todev) {
  200         if ((ret=gp_port_write(port, (char*)data, size)) < GP_OK) {
  201             GP_LOG_E ("scsi_wrap_cmd *** FAILED to write scsi data");
  202             return GP_ERROR_IO;
  203         }
  204     } else {
  205         if ((ret=gp_port_read(port, (char*)data, size)) < GP_OK) {
  206             GP_LOG_E ("scsi_wrap_cmd *** FAILED to read scsi data");
  207             return GP_ERROR_IO;
  208         }
  209     }
  210     if ((ret=usb_wrap_OK(port, &hdr)) != GP_OK) {
  211         GP_LOG_E ("scsi_wrap_cmd *** FAILED to get scsi reply");
  212         return GP_ERROR_IO;
  213     }
  214     return GP_OK;
  215 }
  216 
  217 #define gp_port_send_scsi_cmd scsi_wrap_cmd
  218 
  219 /* Transaction data phase description */
  220 #define PTP_DP_NODATA           0x0000  /* no data phase */
  221 #define PTP_DP_SENDDATA         0x0001  /* sending data */
  222 #define PTP_DP_GETDATA          0x0002  /* receiving data */
  223 #define PTP_DP_DATA_MASK        0x00ff  /* data phase mask */
  224 
  225 static uint16_t
  226 ums_wrap_sendreq (PTPParams* params, PTPContainer* req, int dataphase) {
  227     Camera          *camera = ((PTPData *)params->data)->camera;
  228     PTPUSBBulkContainer usbreq;
  229     char            buf[64];
  230     int         ret;
  231     uw_scsicmd_t        cmd;
  232     char            sense_buffer[32];
  233 
  234     GP_LOG_D ("ums_wrap_sendreq");
  235     /* Build appropriate USB container */
  236     usbreq.length= htod32(PTP_USB_BULK_REQ_LEN-
  237         (sizeof(uint32_t)*(5-req->Nparam)));
  238     usbreq.type = htod16(PTP_USB_CONTAINER_COMMAND);
  239     usbreq.code = htod16(req->Code);
  240     usbreq.trans_id = htod32(req->Transaction_ID);
  241     usbreq.payload.params.param1 = htod32(req->Param1);
  242     usbreq.payload.params.param2 = htod32(req->Param2);
  243     usbreq.payload.params.param3 = htod32(req->Param3);
  244     usbreq.payload.params.param4 = htod32(req->Param4);
  245     usbreq.payload.params.param5 = htod32(req->Param5);
  246 
  247     memset(buf,0,sizeof(buf));
  248 
  249     memset (&cmd, 0, sizeof(cmd));
  250     cmd.cmd    = cmdbyte(0);
  251     cmd.length = uw_value(usbreq.length);
  252 
  253     ret = gp_port_send_scsi_cmd (camera->port, 1, (char*)&cmd, sizeof(cmd),
  254         sense_buffer, sizeof(sense_buffer), (char*)&usbreq, usbreq.length);
  255     GP_LOG_D ("send_scsi_cmd ret %d", ret);
  256     return PTP_RC_OK;
  257 }
  258 
  259 static uint16_t
  260 ums_wrap_senddata (
  261     PTPParams* params, PTPContainer* ptp, uint64_t sendlen, PTPDataHandler*getter
  262 ) {
  263     Camera          *camera = ((PTPData *)params->data)->camera;
  264     PTPUSBBulkContainer usbreq;
  265     int         ret;
  266     unsigned long       gotlen;
  267     unsigned char       *xdata;
  268     uw_scsicmd_t        cmd;
  269     char            sense_buffer[32];
  270 
  271     GP_LOG_D ("ums_wrap_senddata");
  272 
  273     memset (&cmd, 0, sizeof(cmd));
  274     cmd.cmd    = cmdbyte(1);
  275     cmd.length = uw_value(sendlen+12);
  276 
  277     xdata = malloc(sendlen + 12);
  278     usbreq.length = htod32(sendlen + 12);
  279     usbreq.type   = htod16(PTP_USB_CONTAINER_DATA);
  280     usbreq.code   = htod16(ptp->Code);
  281     usbreq.trans_id = htod32(ptp->Transaction_ID);
  282     memcpy (xdata, &usbreq, 12);
  283     ret = getter->getfunc(params, getter->priv, sendlen, xdata+12, &gotlen);
  284     if (ret != PTP_RC_OK) {
  285         GP_LOG_E ("ums_wrap_senddata *** data get from handler FAILED, ret %d", ret);
  286         return ret;
  287     }
  288     if (gotlen != sendlen) {
  289         GP_LOG_E ("ums_wrap_senddata *** data get from handler got %ld instead of %ld", gotlen, sendlen);
  290         return PTP_ERROR_IO;
  291     }
  292 
  293     ret = gp_port_send_scsi_cmd (camera->port, 1, (char*)&cmd, sizeof(cmd),
  294         sense_buffer, sizeof(sense_buffer), (char*)xdata, sendlen+12);
  295 
  296     GP_LOG_D ("send_scsi_cmd ret %d", ret);
  297 
  298     free (xdata);
  299 
  300     return PTP_RC_OK;
  301 }
  302 
  303 static uint16_t
  304 ums_wrap_getresp (PTPParams* params, PTPContainer* resp)
  305 {
  306     Camera          *camera  = ((PTPData *)params->data)->camera;
  307     PTPUSBBulkContainer usbresp;
  308     char            buf[64];
  309     int         ret;
  310     uw_scsicmd_t        cmd;
  311     char            sense_buffer[32];
  312 
  313     GP_LOG_D ("ums_wrap_getresp");
  314     memset (&cmd, 0, sizeof(cmd));
  315     cmd.cmd    = cmdbyte(3);
  316     cmd.length = uw_value(sizeof(buf));
  317 
  318     ret = gp_port_send_scsi_cmd (camera->port, 0, (char*)&cmd, sizeof(cmd),
  319         sense_buffer, sizeof(sense_buffer), (char*)buf, sizeof(buf));
  320 
  321     GP_LOG_D ("send_scsi_cmd ret %d", ret);
  322 
  323     memcpy (&usbresp, buf, sizeof(buf));
  324     resp->Code = dtoh16(usbresp.code);
  325     resp->Nparam = (dtoh32(usbresp.length)-PTP_USB_BULK_REQ_LEN)/sizeof(uint32_t);
  326     resp->Param1 = dtoh32(usbresp.payload.params.param1);
  327     resp->Param2 = dtoh32(usbresp.payload.params.param2);
  328     resp->Param3 = dtoh32(usbresp.payload.params.param3);
  329     resp->Param4 = dtoh32(usbresp.payload.params.param4);
  330     resp->Param5 = dtoh32(usbresp.payload.params.param5);
  331     return PTP_RC_OK;
  332 }
  333 
  334 static uint16_t
  335 ums_wrap_getdata (PTPParams* params, PTPContainer* ptp, PTPDataHandler *putter)
  336 {
  337     Camera          *camera = ((PTPData *)params->data)->camera;
  338     PTPUSBBulkContainer usbresp;
  339     char            buf[64];
  340     int         ret;
  341     unsigned long       recvlen;
  342     char            *data;
  343     uw_scsicmd_t        cmd;
  344     char            sense_buffer[32];
  345 
  346     GP_LOG_D ("ums_wrap_getdata");
  347 
  348     memset(&cmd,0,sizeof(cmd));
  349     cmd.cmd    = cmdbyte(4);
  350     cmd.length = uw_value(sizeof(buf));
  351 
  352     ret = gp_port_send_scsi_cmd (camera->port, 0, (char*)&cmd, sizeof(cmd),
  353         sense_buffer, sizeof(sense_buffer), (char*)buf, sizeof(buf));
  354 
  355     GP_LOG_D ("send_scsi_cmd ret %d", ret);
  356 
  357     memcpy (&usbresp, buf, sizeof(buf));
  358     if ((dtoh16(usbresp.code) != ptp->Code) && (dtoh16(usbresp.code) != PTP_RC_OK)) {
  359         GP_LOG_D ("ums_wrap_getdata *** PTP code %04x during PTP data in size read", dtoh16(usbresp.code));
  360         /* break; */
  361     }
  362     if (dtoh16(usbresp.length) < 16) {
  363         recvlen = 0;
  364         GP_LOG_D ("ums_wrap_getdata *** PTP size %d during PTP data in size read, expected 16", dtoh16(usbresp.length));
  365     } else {
  366         recvlen = dtoh32(usbresp.payload.params.param1);
  367     }
  368     data = malloc (recvlen);
  369     if (!data)
  370         return PTP_ERROR_IO;
  371 
  372     memset(&cmd,0,sizeof(cmd));
  373     cmd.cmd    = cmdbyte(2);
  374     cmd.length = uw_value(recvlen);
  375 
  376     ret = gp_port_send_scsi_cmd (camera->port, 0, (char*)&cmd, sizeof(cmd),
  377         sense_buffer, sizeof(sense_buffer), (char*)data, recvlen);
  378 
  379     GP_LOG_D ("send_scsi_cmd 2 ret  %d", ret);
  380     /* skip away the 12 byte header */
  381     if (recvlen >= 16)
  382         GP_LOG_DATA (data + PTP_USB_BULK_HDR_LEN, recvlen - PTP_USB_BULK_HDR_LEN, "ptp2/olympus/getdata");
  383     ret = putter->putfunc ( params, putter->priv, recvlen - PTP_USB_BULK_HDR_LEN, (unsigned char*)data + PTP_USB_BULK_HDR_LEN);
  384     free (data);
  385     if (ret != PTP_RC_OK) {
  386         GP_LOG_E ("ums_wrap_getdata FAILED to push data into put handle, ret %x", ret);
  387         return PTP_ERROR_IO;
  388     }
  389     return PTP_RC_OK;
  390 }
  391 
  392 static char* generate_event_OK_xml(PTPParams *params, PTPContainer *ptp);
  393 static int parse_event_xml(PTPParams *params, const char *txt, PTPContainer *resp);
  394 
  395 static int
  396 olympus_xml_transfer (PTPParams *params,
  397     char *cmdxml, char **inxml
  398 ) {
  399     PTPContainer    ptp2;
  400     int     res;
  401     PTPObjectInfo   oi;
  402         unsigned char   *resxml, *oidata = NULL;
  403         uint32_t    size, newhandle;
  404     uint16_t    ret;
  405     PTPParams   *outerparams = params->outer_params;
  406 
  407     GP_LOG_D ("olympus_xml_transfer");
  408     while (1) {
  409         GP_LOG_D ("... checking camera for events ...");
  410         ret = outerparams->event_check(outerparams, &ptp2);
  411         if (ret == PTP_RC_OK) {
  412             char *evxml;
  413 
  414             GP_LOG_D ("event: code %04x, p %08x", ptp2.Code, ptp2.Param1);
  415 
  416             if (ptp2.Code != PTP_EC_RequestObjectTransfer) {
  417                 ptp_add_event (params, &ptp2);
  418                 goto skip;
  419             }
  420             newhandle = ptp2.Param1;
  421             if ((newhandle & 0xff000000) != 0x1e000000) {
  422                 GP_LOG_D ("event 0x%04x, handle 0x%08x received, no XML event, just passing on", ptp2.Code, ptp2.Param1);
  423                 ptp_add_event (params, &ptp2);
  424                 continue;
  425             }
  426 
  427             ret = ptp_getobjectinfo (outerparams, newhandle, &oi);
  428             if (ret != PTP_RC_OK)
  429                 return ret;
  430     eventhandler:
  431             GP_LOG_D ("event xml transfer: got new file: %s", oi.Filename);
  432             ret = ptp_getobject (outerparams, newhandle, (unsigned char**)&resxml);
  433             if (ret != PTP_RC_OK)
  434                 return ret;
  435             evxml = malloc (oi.ObjectCompressedSize + 1);
  436             memcpy (evxml, resxml, oi.ObjectCompressedSize);
  437             evxml[oi.ObjectCompressedSize] = 0x00;
  438 
  439             GP_LOG_D ("file content: %s", evxml);
  440 
  441             parse_event_xml (params, evxml, &ptp2);
  442             /* parse it */
  443 
  444             evxml = generate_event_OK_xml(params, &ptp2);
  445 
  446             GP_LOG_D ("... sending XML event reply to camera ... ");
  447             memset (&ptp2, 0 , sizeof (ptp2));
  448             ptp2.Code = PTP_OC_SendObjectInfo;
  449             ptp2.Nparam = 1;
  450             ptp2.Param1 = 0x80000001;
  451 
  452             memset (&oi, 0, sizeof (oi));
  453             oi.ObjectFormat     = PTP_OFC_Script;
  454             oi.StorageID        = 0x80000001;
  455             oi.Filename         = "HRSPONSE.X3C";
  456             oi.ObjectCompressedSize = strlen(evxml);
  457             size = ptp_pack_OI(params, &oi, &oidata);
  458             res = ptp_transaction (outerparams, &ptp2, PTP_DP_SENDDATA, size, &oidata, NULL);
  459             if (res != PTP_RC_OK)
  460                 return res;
  461             free(oidata);
  462             /*handle = ptp2.Param3; ... we do not use the returned handle and leave the file on camera. */
  463 
  464             ptp2.Code = PTP_OC_SendObject;
  465             ptp2.Nparam = 0;
  466             res = ptp_transaction(outerparams, &ptp2, PTP_DP_SENDDATA, strlen(evxml), (unsigned char**)&evxml, NULL);
  467             if (res != PTP_RC_OK)
  468                 return res;
  469             continue;
  470         }
  471     skip:
  472 
  473         GP_LOG_D ("... sending XML request to camera ... ");
  474         memset (&ptp2, 0 , sizeof (ptp2));
  475         ptp2.Code = PTP_OC_SendObjectInfo;
  476         ptp2.Nparam = 1;
  477         ptp2.Param1 = 0x80000001;
  478 
  479         memset (&oi, 0, sizeof (oi));
  480         oi.ObjectFormat     = PTP_OFC_Script;
  481         oi.StorageID        = 0x80000001;
  482         oi.Filename         = "HREQUEST.X3C";
  483         oi.ObjectCompressedSize = strlen(cmdxml);
  484 
  485 /*
  486 "HRSPONSE.X3C" ... sent back to camera after receiving an event.
  487 <output><result>2001</result><ec102/></output
  488  */
  489 
  490         size = ptp_pack_OI(params, &oi, &oidata);
  491         res = ptp_transaction (outerparams, &ptp2, PTP_DP_SENDDATA, size, &oidata, NULL);
  492         if (res != PTP_RC_OK)
  493             return res;
  494         free(oidata);
  495         /*handle = ptp2.Param3; ... we do not use the returned handle and leave the file on camera. */
  496 
  497         ptp2.Code = PTP_OC_SendObject;
  498         ptp2.Nparam = 0;
  499         res = ptp_transaction(outerparams, &ptp2, PTP_DP_SENDDATA, strlen(cmdxml), (unsigned char**)&cmdxml, NULL);
  500         if (res != PTP_RC_OK)
  501             return res;
  502 
  503         GP_LOG_D ("... waiting for camera ...");
  504 redo:
  505         ret = outerparams->event_wait(outerparams, &ptp2);
  506         if (ret != PTP_RC_OK)
  507             return ret;
  508         GP_LOG_D ("event: code %04x, p %08x", ptp2.Code, ptp2.Param1);
  509         if (ptp2.Code != PTP_EC_RequestObjectTransfer) {
  510             ptp_add_event (params, &ptp2);
  511             goto redo;
  512         }
  513         /* FIXME: check for 0x1e0000* ? */
  514         newhandle = ptp2.Param1;
  515         ret = ptp_getobjectinfo (outerparams, newhandle, &oi);
  516         if (ret != PTP_RC_OK)
  517             return ret;
  518         GP_LOG_D ("regular xml transfer: got new file: %s", oi.Filename);
  519         if (strcmp(oi.Filename,"DRSPONSE.X3C")) {
  520             GP_LOG_E ("FIXME: regular xml transfer: got new file: %s", oi.Filename);
  521             goto eventhandler;
  522         }
  523         ret = ptp_getobject (outerparams, newhandle, (unsigned char**)&resxml);
  524         if (ret != PTP_RC_OK)
  525             return ret;
  526         *inxml = malloc (oi.ObjectCompressedSize + 1);
  527         memcpy (*inxml, resxml, oi.ObjectCompressedSize);
  528         (*inxml)[oi.ObjectCompressedSize] = 0x00;
  529 
  530         GP_LOG_D ("file content: %s", *inxml);
  531         /* parse it */
  532         break;
  533     }
  534     return PTP_RC_OK;
  535 }
  536 
  537 static int
  538 traverse_tree (PTPParams *params, int depth, xmlNodePtr node) {
  539     xmlNodePtr  next;
  540     xmlChar     *xchar;
  541     int n;
  542     char        *xx;
  543 
  544 
  545     if (!node) return FALSE;
  546     xx = malloc(depth * 4 + 1);
  547     memset (xx, ' ', depth*4);
  548     xx[depth*4] = 0;
  549 
  550     n = xmlChildElementCount (node);
  551 
  552     next = node;
  553     do {
  554         ptp_debug(params,"%snode %s", xx, next->name);
  555         ptp_debug(params,"%selements %d", xx, n);
  556         xchar = xmlNodeGetContent (next);
  557         ptp_debug(params,"%scontent %s", xx, xchar);
  558         traverse_tree (params, depth+1,xmlFirstElementChild (next));
  559     } while ((next = xmlNextElementSibling (next)));
  560     free (xx);
  561     return TRUE;
  562 }
  563 
  564 static int
  565 parse_9581_tree (xmlNodePtr node) {
  566     xmlNodePtr next;
  567 
  568     next = xmlFirstElementChild (node);
  569     while (next) {
  570         if (!strcmp ((char*)next->name, "data")) {
  571             char *decoded, *x;
  572             char *xchars = (char*)xmlNodeGetContent (next);
  573 
  574             x = decoded = malloc(strlen(xchars)+1);
  575             while (xchars[0] && xchars[1]) {
  576                 int y;
  577                 sscanf(xchars,"%02x", &y);
  578                 *x++ = y;
  579                 xchars+=2;
  580             }
  581             *x = '\0';
  582             GP_LOG_D ("9581: %s", decoded);
  583 
  584 
  585             next = xmlNextElementSibling (next);
  586             free (decoded);
  587             continue;
  588         }
  589         GP_LOG_E ("9581: unhandled node type %s", next->name);
  590         next = xmlNextElementSibling (next);
  591     }
  592     /*traverse_tree (0, node);*/
  593     return TRUE;
  594 }
  595 
  596 static int
  597 parse_910a_tree (xmlNodePtr node) {
  598     xmlNodePtr next;
  599 
  600     next = xmlFirstElementChild (node);
  601     do {
  602         if (!strcmp ((char*)next->name, "param")) {
  603             unsigned int x;
  604             xmlChar *xchar = xmlNodeGetContent (next);
  605             if (!sscanf((char*)xchar,"%08x", &x)) {
  606                 fprintf(stderr,"could not parse param content %s\n", xchar);
  607             }
  608             fprintf(stderr,"param content is 0x%08x\n", x);
  609             continue;
  610         }
  611         fprintf (stderr,"910a: unhandled type %s\n", next->name);
  612     } while ((next = xmlNextElementSibling (next)));
  613     /*traverse_tree (0, node);*/
  614     return TRUE;
  615 }
  616 
  617 static int
  618 parse_9302_tree (xmlNodePtr node) {
  619     xmlNodePtr  next;
  620     xmlChar     *xchar;
  621 
  622     next = xmlFirstElementChild (node);
  623     while (next) {
  624         if (!strcmp((char*)next->name, "x3cVersion")) {
  625             int x3cver;
  626             xchar = xmlNodeGetContent (next);
  627             sscanf((char*)xchar, "%04x", &x3cver);
  628             GP_LOG_D ("x3cVersion %d.%d", (x3cver>>8)&0xff, x3cver&0xff);
  629             goto xnext;
  630         }
  631         if (!strcmp((char*)next->name, "productIDs")) {
  632             char *x, *nextspace;
  633             int len;
  634             x = (char*)(xchar = xmlNodeGetContent (next));
  635             GP_LOG_D ("productIDs:");
  636 
  637             do {
  638                 nextspace=strchr(x,' ');
  639                 if (nextspace) nextspace++;
  640 
  641                 /* ascii ptp string, 1 byte length, little endian 16 bit chars */
  642                 if (sscanf(x,"%02x", &len)) {
  643                     int i;
  644                     char *str = malloc(len+1);
  645                     for (i=0;i<len;i++) {
  646                         int xc;
  647                         if (sscanf(x+2+i*4,"%04x", &xc)) {
  648                             int cx;
  649 
  650                             cx = ((xc>>8) & 0xff) | ((xc & 0xff) << 8);
  651                             str[i] = cx;
  652                         }
  653                         str[len] = 0;
  654                     }
  655                     GP_LOG_D ("\t%s", str);
  656                     free (str);
  657                 }
  658                 x = nextspace;
  659             } while (x);
  660 
  661             goto xnext;
  662         }
  663         GP_LOG_E ("unknown node in 9301: %s", next->name);
  664 xnext:
  665         next = xmlNextElementSibling (next);
  666     }
  667     return TRUE;
  668 }
  669 
  670 #if 0
  671 static int
  672 parse_9301_value (PTPParams *params, const char *str, uint16_t type, PTPPropertyValue *propval) {
  673     switch (type) {
  674     case 6: { /*UINT32*/
  675         unsigned int x;
  676         if (!sscanf(str,"%08x", &x)) {
  677             ptp_debug( params, "could not parse uint32 %s", str);
  678             return PTP_RC_GeneralError;
  679         }
  680         ptp_debug( params, "\t%d", x);
  681         propval->u32 = x;
  682         break;
  683     }
  684     case 5: { /*INT32*/
  685         int x;
  686         if (!sscanf(str,"%08x", &x)) {
  687             ptp_debug( params, "could not parse int32 %s", str);
  688             return PTP_RC_GeneralError;
  689         }
  690         ptp_debug( params, "\t%d", x);
  691         propval->i32 = x;
  692         break;
  693     }
  694     case 4: { /*UINT16*/
  695         unsigned int x;
  696         if (!sscanf(str,"%04x", &x)) {
  697             ptp_debug( params, "could not parse uint16 %s", str);
  698             return PTP_RC_GeneralError;
  699         }
  700         ptp_debug( params, "\t%d", x);
  701         propval->u16 = x;
  702         break;
  703     }
  704     case 3: { /*INT16*/
  705         int x;
  706         if (!sscanf(str,"%04x", &x)) {
  707             ptp_debug( params, "could not parse int16 %s", str);
  708             return PTP_RC_GeneralError;
  709         }
  710         ptp_debug( params, "\t%d", x);
  711         propval->i16 = x;
  712         break;
  713     }
  714     case 2: { /*UINT8*/
  715         unsigned int x;
  716         if (!sscanf(str,"%02x", &x)) {
  717             ptp_debug( params, "could not parse uint8 %s", str);
  718             return PTP_RC_GeneralError;
  719         }
  720         ptp_debug( params, "\t%d", x);
  721         propval->u8 = x;
  722         break;
  723     }
  724     case 1: { /*INT8*/
  725         int x;
  726         if (!sscanf(str,"%02x", &x)) {
  727             ptp_debug( params, "could not parse int8 %s", str);
  728             return PTP_RC_GeneralError;
  729         }
  730         ptp_debug( params, "\t%d", x);
  731         propval->i8 = x;
  732         break;
  733     }
  734     case 65535: { /* string */
  735         int len;
  736 
  737         /* ascii ptp string, 1 byte length, little endian 16 bit chars */
  738         if (sscanf(str,"%02x", &len)) {
  739             int i;
  740             char *xstr = malloc(len+1);
  741             for (i=0;i<len;i++) {
  742                 int xc;
  743                 if (sscanf(str+2+i*4,"%04x", &xc)) {
  744                     int cx;
  745 
  746                     cx = ((xc>>8) & 0xff) | ((xc & 0xff) << 8);
  747                     xstr[i] = cx;
  748                 }
  749                 xstr[len] = 0;
  750             }
  751             ptp_debug( params, "\t%s", xstr);
  752             propval->str = xstr;
  753             break;
  754         }
  755         ptp_debug( params, "string %s not parseable!", str);
  756         return PTP_RC_GeneralError;
  757     }
  758     case 7: /*INT64*/
  759     case 8: /*UINT64*/
  760     case 9: /*INT128*/
  761     case 10: /*UINT128*/
  762     default:
  763         ptp_debug( params, "unhandled data type %d!", type);
  764         return PTP_RC_GeneralError;
  765     }
  766     return PTP_RC_OK;
  767 }
  768 
  769 
  770 static int
  771 parse_9301_propdesc (PTPParams *params, xmlNodePtr node, PTPDevicePropDesc *dpd) {
  772     xmlNodePtr next;
  773     int type = -1;
  774 
  775     dpd->FormFlag   = PTP_DPFF_None;
  776     dpd->GetSet = PTP_DPGS_Get;
  777     next = xmlFirstElementChild (node);
  778     do {
  779         if (!strcmp((char*)next->name,"type")) {    /* propdesc.DataType */
  780             if (!sscanf((char*)xmlNodeGetContent (next), "%04x", &type)) {
  781                 ptp_debug( params, "\ttype %s not parseable?",xmlNodeGetContent (next));
  782                 return 0;
  783             }
  784             ptp_debug( params, "type 0x%x", type);
  785             dpd->DataType = type;
  786             continue;
  787         }
  788         if (!strcmp((char*)next->name,"attribute")) {   /* propdesc.GetSet */
  789             int attr;
  790 
  791             if (!sscanf((char*)xmlNodeGetContent (next), "%02x", &attr)) {
  792                 ptp_debug( params, "\tattr %s not parseable",xmlNodeGetContent (next));
  793                 return 0;
  794             }
  795             ptp_debug( params, "attribute 0x%x", attr);
  796             dpd->GetSet = attr;
  797             continue;
  798         }
  799         if (!strcmp((char*)next->name,"default")) { /* propdesc.FactoryDefaultValue */
  800             ptp_debug( params, "default value");
  801             parse_9301_value (params, (char*)xmlNodeGetContent (next), type, &dpd->FactoryDefaultValue);
  802             continue;
  803         }
  804         if (!strcmp((char*)next->name,"value")) {   /* propdesc.CurrentValue */
  805             ptp_debug( params, "current value");
  806             parse_9301_value (params, (char*)xmlNodeGetContent (next), type, &dpd->CurrentValue);
  807             continue;
  808         }
  809         if (!strcmp((char*)next->name,"enum")) {    /* propdesc.FORM.Enum */
  810             int n,i;
  811             char *s;
  812 
  813             ptp_debug( params, "enum");
  814             dpd->FormFlag = PTP_DPFF_Enumeration;
  815             s = (char*)xmlNodeGetContent (next);
  816             n = 0;
  817             do {
  818                 s = strchr(s,' ');
  819                 if (s) s++;
  820                 n++;
  821             } while (s);
  822             dpd->FORM.Enum.NumberOfValues = n;
  823             dpd->FORM.Enum.SupportedValue = calloc (n , sizeof(PTPPropertyValue));
  824             s = (char*)xmlNodeGetContent (next);
  825             i = 0;
  826             do {
  827                 parse_9301_value (params, s, type, &dpd->FORM.Enum.SupportedValue[i]); /* should turn ' ' into \0? */
  828                 i++;
  829                 s = strchr(s,' ');
  830                 if (s) s++;
  831             } while (s && (i<n));
  832             continue;
  833         }
  834         if (!strcmp((char*)next->name,"range")) {   /* propdesc.FORM.Enum */
  835             char *s = (char*)xmlNodeGetContent (next);
  836             dpd->FormFlag = PTP_DPFF_Range;
  837             ptp_debug( params, "range");
  838             parse_9301_value (params, s, type, &dpd->FORM.Range.MinimumValue); /* should turn ' ' into \0? */
  839             s = strchr(s,' ');
  840             if (!s) continue;
  841             s++;
  842             parse_9301_value (params, s, type, &dpd->FORM.Range.MaximumValue); /* should turn ' ' into \0? */
  843             s = strchr(s,' ');
  844             if (!s) continue;
  845             s++;
  846             parse_9301_value (params, s, type, &dpd->FORM.Range.StepSize); /* should turn ' ' into \0? */
  847 
  848             continue;
  849         }
  850         ptp_debug (params, "\tpropdescvar: %s", next->name);
  851         ptp_debug (params, "\tcontent: %s", (char*)xmlNodeGetContent(next));
  852         traverse_tree (params, 3, xmlFirstElementChild(next));
  853     } while ((next = xmlNextElementSibling (next)));
  854     return PTP_RC_OK;
  855 }
  856 
  857 static int
  858 parse_1015_tree (xmlNodePtr node, uint16_t type) {
  859     PTPPropertyValue    propval;
  860     xmlNodePtr      next;
  861 
  862     next = xmlFirstElementChild (node);
  863     return parse_value ((char*)xmlNodeGetContent (next), type, &propval);
  864 }
  865 #endif
  866 
  867 static int
  868 traverse_output_tree (PTPParams *params, xmlNodePtr node, PTPContainer *resp) {
  869     xmlNodePtr next;
  870     int cmd;
  871 
  872     if (strcmp((char*)node->name,"output")) {
  873         GP_LOG_E ("node is not output, but %s.", node->name);
  874         return FALSE;
  875     }
  876     if (xmlChildElementCount(node) != 2) {
  877         GP_LOG_E ("output: expected 2 children, got %ld.", xmlChildElementCount(node));
  878         return FALSE;
  879     }
  880     next = xmlFirstElementChild (node);
  881     if (!strcmp((char*)next->name,"result")) {
  882         int result;
  883         xmlChar *xchar;
  884         xchar = xmlNodeGetContent (next);
  885         if (!sscanf((char*)xchar,"%04x",&result))
  886             GP_LOG_E ("failed scanning result from %s", xchar);
  887         resp->Code = result;
  888         GP_LOG_D ("ptp result is 0x%04x", result);
  889 
  890     }
  891     next = xmlNextElementSibling (next);
  892     if (!sscanf ((char*)next->name, "c%04x", &cmd)) {
  893         GP_LOG_E ("expected c<HEX>, have %s", next->name);
  894         return FALSE;
  895     }
  896     GP_LOG_D ("cmd is 0x%04x", cmd);
  897     switch (cmd) {
  898     /* reviewed OK. */
  899     case PTP_OC_OLYMPUS_Capture:    return TRUE;
  900     case PTP_OC_GetDevicePropDesc:  return TRUE;
  901 
  902     /* TODO */
  903 #if 0
  904     case PTP_OC_OLYMPUS_GetDeviceInfo: return parse_9301_tree (next); /* 9301 */
  905 #endif
  906     case PTP_OC_OLYMPUS_OpenSession: return parse_9302_tree (next);
  907     case PTP_OC_OLYMPUS_GetCameraControlMode: return parse_910a_tree (next);
  908     case PTP_OC_OLYMPUS_GetCameraID: return parse_9581_tree (next);
  909 
  910     case PTP_OC_SetDevicePropValue: /* <output>\n<result>2001</result>\n<c1016>\n<pD135/>\n</c1016>\n</output> */
  911         /* we could cross check the parameter, but its not strictly necessary */
  912         return TRUE;
  913 #if 0
  914     case PTP_OC_GetDevicePropValue: return parse_1015_tree ( next , PTP_DTC_UINT32);
  915 #endif
  916     default:
  917         return traverse_tree (params, 0, next);
  918     }
  919     return FALSE;
  920 }
  921 
  922 static int
  923 traverse_input_tree (PTPParams *params, xmlNodePtr node, PTPContainer *resp) {
  924     unsigned int    curpar = 0;
  925     int     evt;
  926     xmlNodePtr  next = xmlFirstElementChild (node);
  927     uint32_t    pars[5];
  928 
  929 
  930     if (!next) {
  931         GP_LOG_E ("no nodes below input.");
  932         return FALSE;
  933     }
  934 
  935     resp->Code = 0;
  936     while (next) {
  937         if (sscanf((char*)next->name,"e%x",&evt)) {
  938             resp->Code = evt;
  939 
  940             switch (evt) {
  941             case PTP_EC_Olympus_PropertyChanged: {
  942                 xmlNodePtr propidnode = xmlFirstElementChild(next);
  943 
  944                 /* Gets a list of property that changed ... stuff into
  945                  * event queue. */
  946                 while (propidnode) {
  947                     int propid;
  948 
  949                     if (sscanf((char*)propidnode->name,"p%x", &propid)) {
  950                         PTPContainer ptp;
  951 
  952                         memset(&ptp, 0, sizeof(ptp));
  953                         ptp.Code = PTP_EC_DevicePropChanged;
  954                         ptp.Nparam = 1;
  955                         ptp.Param1 = propid;
  956                         ptp_add_event (params, &ptp);
  957                     }
  958                     propidnode = xmlNextElementSibling (propidnode);
  959                 }
  960                 break;
  961             }
  962             default:
  963                 if (xmlChildElementCount(node) != 0) {
  964                     GP_LOG_E ("event %s hat tree below?", (char*)next->name);
  965                     traverse_tree (params, 0, xmlFirstElementChild(next));
  966                 }
  967             }
  968             next = xmlNextElementSibling (next);
  969             continue;
  970         }
  971         if (!strcmp((char*)next->name,"param")) {
  972             int x;
  973             if (sscanf((char*)xmlNodeGetContent(next),"%x", &x)) {
  974                 if (curpar < sizeof(pars)/sizeof(pars[0]))
  975                     pars[curpar++] = x;
  976                 else
  977                     GP_LOG_E ("ignore superfluous argument %s/%x", (char*)xmlNodeGetContent(next), x);
  978             }
  979             next = xmlNextElementSibling (next);
  980             continue;
  981         }
  982         GP_LOG_E ("parsing event input node, unknown node %s", (char*)next->name);
  983         next = xmlNextElementSibling (next);
  984     }
  985     resp->Nparam = curpar;
  986     switch (curpar) {
  987     case 5: resp->Param5 = pars[4]; /* fallthrough */
  988     case 4: resp->Param4 = pars[3]; /* fallthrough */
  989     case 3: resp->Param3 = pars[2]; /* fallthrough */
  990     case 2: resp->Param2 = pars[1]; /* fallthrough */
  991     case 1: resp->Param1 = pars[0]; /* fallthrough */
  992     case 0: break;
  993     }
  994     /* FIXME: decode content and inject into PTP event queue. */
  995     return TRUE;
  996 }
  997 
  998 static int
  999 traverse_x3c_tree (PTPParams *params, xmlNodePtr node, PTPContainer *resp) {
 1000     xmlNodePtr  next;
 1001 
 1002     if (!node)
 1003         return FALSE;
 1004     if (strcmp((char*)node->name,"x3c")) {
 1005         GP_LOG_E ("node is not x3c, but %s.", node->name);
 1006         return FALSE;
 1007     }
 1008     if (xmlChildElementCount(node) != 1) {
 1009         GP_LOG_E ("x3c: expected 1 child, got %ld.", xmlChildElementCount(node));
 1010         return FALSE;
 1011     }
 1012     next = xmlFirstElementChild (node);
 1013     if (!strcmp((char*)next->name, "output"))
 1014         return traverse_output_tree (params, next, resp);
 1015     if (!strcmp((char*)next->name, "input"))
 1016         return traverse_input_tree (params, next, resp); /* event */
 1017     GP_LOG_E ("unknown name %s below x3c.", next->name);
 1018     return FALSE;
 1019 }
 1020 
 1021 static int
 1022 traverse_x3c_event_tree (PTPParams *params, xmlNodePtr node, PTPContainer *resp) {
 1023     xmlNodePtr  next;
 1024 
 1025     if (!node)
 1026         return FALSE;
 1027     if (strcmp((char*)node->name,"x3c")) {
 1028         GP_LOG_E ("node is not x3c, but %s.", node->name);
 1029         return FALSE;
 1030     }
 1031     if (xmlChildElementCount(node) != 1) {
 1032         GP_LOG_E ("x3c: expected 1 child, got %ld.", xmlChildElementCount(node));
 1033         return FALSE;
 1034     }
 1035     next = xmlFirstElementChild (node);
 1036     if (!strcmp((char*)next->name, "input"))
 1037         return traverse_input_tree (params, next, resp); /* event */
 1038     GP_LOG_E ("unknown name %s below x3c.", next->name);
 1039     return FALSE;
 1040 }
 1041 
 1042 static int
 1043 parse_xml(PTPParams *params, const char *txt, PTPContainer *resp) {
 1044     xmlDocPtr   docin;
 1045     xmlNodePtr  docroot;
 1046 
 1047     docin = xmlReadMemory (txt, strlen(txt), "http://gphoto.org/", "utf-8", 0);
 1048     if (!docin) return FALSE;
 1049     docroot = xmlDocGetRootElement (docin);
 1050     if (!docroot) return FALSE;
 1051     return traverse_x3c_tree (params, docroot, resp);
 1052 }
 1053 
 1054 static int
 1055 parse_event_xml(PTPParams *params, const char *txt, PTPContainer *resp) {
 1056     xmlDocPtr   docin;
 1057     xmlNodePtr  docroot;
 1058 
 1059     docin = xmlReadMemory (txt, strlen(txt), "http://gphoto.org/", "utf-8", 0);
 1060     if (!docin) return FALSE;
 1061     docroot = xmlDocGetRootElement (docin);
 1062     if (!docroot) return FALSE;
 1063     return traverse_x3c_event_tree (params, docroot, resp);
 1064 }
 1065 
 1066 static void
 1067 encode_command (xmlNodePtr inputnode, PTPContainer *ptp, unsigned char *data, int len)
 1068 {
 1069     xmlNodePtr  cmdnode;
 1070     char        code[20];
 1071 
 1072     sprintf(code,"c%04X", ptp->Code);
 1073     cmdnode     = xmlNewChild (inputnode, NULL, (xmlChar*)code, NULL);
 1074 
 1075     switch (ptp->Code) {
 1076     case 0x1014: { /* OK */
 1077         sprintf (code, "p%04X", ptp->Param1);
 1078         xmlNewChild (cmdnode, NULL, (xmlChar*)code, NULL);
 1079         break;
 1080     }
 1081     case 0x1016: {
 1082         char buf[20];
 1083         xmlNodePtr  pnode;
 1084         /* zb <c1016><pD10D><value>000A000D</value></pD10D></c1016> */
 1085         /* FIXME: might still be wrong. */
 1086         /* We can directly byte encode the data we get from the PTP stack */
 1087         /* ... BUT the byte order is bigendian (printed) vs encoded */
 1088         int i;
 1089         char *x = malloc (len*2+1);
 1090 
 1091         if (len <= 4) { /* just dump the bytes in big endian byteorder */
 1092             for (i=0;i<len;i++)
 1093                 sprintf(x+2*i,"%02X",data[len-i-1]);
 1094         } else {
 1095             for (i=0;i<len;i++)
 1096                 sprintf(x+2*i,"%02X",data[i]);
 1097         }
 1098         sprintf(buf,"p%04X", ptp->Param1);
 1099         pnode = xmlNewChild (cmdnode, NULL, (xmlChar*)buf, NULL);
 1100         xmlNewChild (pnode, NULL, (xmlChar*)"value", (xmlChar*)x);
 1101         free (x);
 1102         break;
 1103     }
 1104     default:
 1105         if (ptp->Nparam) {
 1106             switch (ptp->Nparam) {
 1107             case 1:
 1108                 sprintf (code, "%08X", ptp->Param1);
 1109                 xmlNewChild (cmdnode, NULL, (xmlChar*)"param", (xmlChar*)code);
 1110                 break;
 1111             case 2:
 1112                 sprintf (code, "%08X", ptp->Param1);
 1113                 xmlNewChild (cmdnode, NULL, (xmlChar*)"param", (xmlChar*)code);
 1114                 sprintf (code, "%08X", ptp->Param2);
 1115                 xmlNewChild (cmdnode, NULL, (xmlChar*)"param", (xmlChar*)code);
 1116                 break;
 1117             }
 1118         }
 1119         break;
 1120     }
 1121 }
 1122 
 1123 static char*
 1124 generate_event_OK_xml(PTPParams *params, PTPContainer *ptp) {
 1125     xmlDocPtr   docout;
 1126     xmlChar     *output;
 1127     int     len;
 1128     xmlNodePtr  x3cnode, inputnode;
 1129     char        buf[10];
 1130 
 1131     /*
 1132     "HRSPONSE.X3C" ... sent back to camera after receiving an event.
 1133     <output><result>2001</result><ec102/></output
 1134      */
 1135 
 1136     docout      = xmlNewDoc ((xmlChar*)"1.0");
 1137     x3cnode     = xmlNewDocNode (docout, NULL, (xmlChar*)"x3c", NULL);
 1138                       xmlNewNs (x3cnode,(xmlChar*)"http://www1.olympus-imaging.com/ww/x3c",NULL);
 1139     inputnode   = xmlNewChild (x3cnode, NULL, (xmlChar*)"output", NULL);
 1140 
 1141     sprintf (buf,"e%04X", ptp->Code);
 1142 
 1143     xmlNewChild (inputnode,  NULL, (xmlChar*)"result", (xmlChar*)"2001");
 1144     xmlNewChild (inputnode,  NULL, (xmlChar*)buf, NULL);
 1145 
 1146     xmlDocSetRootElement (docout, x3cnode);
 1147     xmlDocDumpMemory (docout, &output, &len);
 1148 
 1149     GP_LOG_D ("generated xml is:");
 1150     GP_LOG_D ("%s", output);
 1151 
 1152     /* NOTE: Windows driver generates XML with CRLF, Unix just creates XML with LF.
 1153      * Olympus E-410 does not seem to care. */
 1154     return (char*)output;
 1155 }
 1156 static char*
 1157 generate_xml(PTPParams *params, PTPContainer *ptp, unsigned char *data, int len) {
 1158     xmlDocPtr   docout;
 1159     xmlChar     *output;
 1160     xmlNodePtr  x3cnode;
 1161     xmlNodePtr  inputnode;
 1162 
 1163     docout      = xmlNewDoc ((xmlChar*)"1.0");
 1164     x3cnode     = xmlNewDocNode (docout, NULL, (xmlChar*)"x3c", NULL);
 1165                       xmlNewNs (x3cnode,(xmlChar*)"http://www1.olympus-imaging.com/ww/x3c",NULL);
 1166     inputnode   = xmlNewChild (x3cnode, NULL, (xmlChar*)"input", NULL);
 1167 
 1168     /* The fun starts in here: */
 1169     encode_command (inputnode, ptp, data, len);
 1170 
 1171     xmlDocSetRootElement (docout, x3cnode);
 1172     xmlDocDumpMemory (docout, &output, &len);
 1173 
 1174     GP_LOG_D ("generated xml is:");
 1175     GP_LOG_D ("%s", output);
 1176 
 1177     /* NOTE: Windows driver generates XML with CRLF, Unix just creates XML with LF.
 1178      * Olympus E-410 does not seem to care. */
 1179     return (char*)output;
 1180 }
 1181 
 1182 static int
 1183 is_outer_operation (PTPParams* params, uint16_t opcode) {
 1184     unsigned int i;
 1185 
 1186     GP_LOG_D ("is_outer_operation %04x", opcode);
 1187     /* the ones we need before we can do getdeviceinfo */
 1188     if (opcode == PTP_OC_OpenSession)   return 1;
 1189     if (opcode == PTP_OC_SendObjectInfo)    return 1;
 1190     if (opcode == PTP_OC_SendObject)    return 1;
 1191     if (opcode == PTP_OC_GetDeviceInfo) return 1;
 1192     if (opcode == PTP_OC_GetStorageIDs) return 1;
 1193 
 1194     /* all vendor ones are XML driven. */
 1195     if ((opcode & 0x8000) == 0x8000) return 0;
 1196 
 1197     /* Do nothing here, either do stuff in senddata, getdata or getresp,
 1198      * which will get the PTPContainer req too. */
 1199         for (i=0;i<params->outer_deviceinfo.OperationsSupported_len;i++)
 1200                 if (params->outer_deviceinfo.OperationsSupported[i]==opcode)
 1201                         return TRUE;
 1202     GP_LOG_D ("is_outer_operation %04x - is WRAPPED", opcode);
 1203     return FALSE;
 1204 }
 1205 
 1206 static uint16_t
 1207 ums_wrap2_event_check (PTPParams* params, PTPContainer* req)
 1208 {
 1209     PTPContainer    ptp2;
 1210     int     res;
 1211     PTPObjectInfo   oi;
 1212         unsigned char   *resxml, *oidata = NULL;
 1213         uint32_t    size, newhandle;
 1214     uint16_t    ret;
 1215     PTPParams   *outerparams = params->outer_params;
 1216     char        *evxml;
 1217 
 1218     GP_LOG_D ("ums_wrap2_event_check");
 1219 
 1220     while (1) {
 1221         ret = outerparams->event_check(outerparams, &ptp2);
 1222         if (ret != PTP_RC_OK)
 1223             return ret;
 1224 
 1225         GP_LOG_D ("event: code %04x, p %08x", ptp2.Code, ptp2.Param1);
 1226 
 1227         if (ptp2.Code != PTP_EC_RequestObjectTransfer) {
 1228             GP_LOG_D ("event 0x%04x received, just passing on", ptp2.Code);
 1229             memcpy (req, &ptp2, sizeof(ptp2));
 1230             return PTP_RC_OK;
 1231         }
 1232 
 1233         newhandle = ptp2.Param1;
 1234 
 1235         if ((newhandle & 0xff000000) != 0x1e000000) {
 1236             GP_LOG_D ("event 0x%04x, handle 0x%08x received, no XML event, just passing on", ptp2.Code, ptp2.Param1);
 1237             ptp_add_event (params, &ptp2);
 1238             continue;
 1239         }
 1240 
 1241         ret = ptp_getobjectinfo (outerparams, newhandle, &oi);
 1242         if (ret != PTP_RC_OK)
 1243             return ret;
 1244         GP_LOG_D ("event xml: got new file: %s", oi.Filename);
 1245         if (!strstr(oi.Filename,".X3C")) {
 1246             GP_LOG_D ("PTP_EC_RequestObjectTransfer with non XML filename %s", oi.Filename);
 1247             memcpy (req, &ptp2, sizeof(ptp2));
 1248             return PTP_RC_OK;
 1249         }
 1250         ret = ptp_getobject (outerparams, newhandle, (unsigned char**)&resxml);
 1251         if (ret != PTP_RC_OK)
 1252             return ret;
 1253         evxml = malloc (oi.ObjectCompressedSize + 1);
 1254         memcpy (evxml, resxml, oi.ObjectCompressedSize);
 1255         evxml[oi.ObjectCompressedSize] = 0x00;
 1256 
 1257         GP_LOG_D ("file content: %s", evxml);
 1258 
 1259         /* FIXME: handle the case where we get a non X3C file, like during capture */
 1260 
 1261         /* parse it  ... into req */
 1262         parse_event_xml (params, evxml, req);
 1263 
 1264         /* generate reply */
 1265         evxml = generate_event_OK_xml(params, req);
 1266 
 1267         GP_LOG_D ("... sending XML event reply to camera ... ");
 1268         memset (&ptp2, 0 , sizeof (ptp2));
 1269         ptp2.Code = PTP_OC_SendObjectInfo;
 1270         ptp2.Nparam = 1;
 1271         ptp2.Param1 = 0x80000001;
 1272 
 1273         memset (&oi, 0, sizeof (oi));
 1274         oi.ObjectFormat     = PTP_OFC_Script;
 1275         oi.StorageID        = 0x80000001;
 1276         oi.Filename         = "HRSPONSE.X3C";
 1277         oi.ObjectCompressedSize = strlen(evxml);
 1278         size = ptp_pack_OI(params, &oi, &oidata);
 1279         res = ptp_transaction (outerparams, &ptp2, PTP_DP_SENDDATA, size, &oidata, NULL);
 1280         if (res != PTP_RC_OK)
 1281             return res;
 1282         free(oidata);
 1283         /*handle = ptp2.Param3; ... we do not use the returned handle and leave the file on camera. */
 1284 
 1285         ptp2.Code = PTP_OC_SendObject;
 1286         ptp2.Nparam = 0;
 1287         res = ptp_transaction(outerparams, &ptp2, PTP_DP_SENDDATA, strlen(evxml), (unsigned char**)&evxml, NULL);
 1288         if (res != PTP_RC_OK)
 1289             return res;
 1290         return PTP_RC_OK;
 1291     }
 1292 }
 1293 
 1294 static uint16_t
 1295 ums_wrap2_sendreq (PTPParams* params, PTPContainer* req, int dataphase)
 1296 {
 1297     GP_LOG_D ("ums_wrap2_sendreq");
 1298     if (is_outer_operation (params,req->Code))
 1299         return ums_wrap_sendreq (params,req,dataphase);
 1300     /* We do stuff in either senddata, getdata or getresp, not here. */
 1301     params->olympus_cmd   = NULL;
 1302     params->olympus_reply = NULL;
 1303     return PTP_RC_OK;
 1304 }
 1305 
 1306 static uint16_t
 1307 ums_wrap2_senddata (
 1308     PTPParams* params, PTPContainer* ptp, uint64_t sendlen, PTPDataHandler*getter
 1309 ) {
 1310     unsigned char   *data;
 1311     uint16_t    ret;
 1312     unsigned long   gotlen;
 1313 
 1314     if (is_outer_operation (params, ptp->Code))
 1315         return ums_wrap_senddata (params, ptp, sendlen, getter);
 1316 
 1317     GP_LOG_D ("ums_wrap2_senddata");
 1318     data = malloc (sendlen);
 1319     ret = getter->getfunc(params, getter->priv, sendlen, data, &gotlen);
 1320     if (ret != PTP_RC_OK) {
 1321         GP_LOG_D ("ums_wrap2_senddata *** data get from handler FAILED, ret %d", ret);
 1322         return ret;
 1323     }
 1324     params->olympus_cmd = generate_xml (params, ptp, data, sendlen);
 1325     free (data);
 1326     /* Do not do stuff yet, do it in getresp */
 1327     return PTP_RC_OK;
 1328 }
 1329 
 1330 static uint16_t
 1331 ums_wrap2_getdata (PTPParams* params, PTPContainer* ptp, PTPDataHandler *putter) {
 1332     char        *resxml = NULL;
 1333     uint16_t    ret;
 1334 
 1335     if (is_outer_operation (params, ptp->Code))
 1336         return ums_wrap_getdata (params, ptp, putter);
 1337 
 1338     GP_LOG_D ("ums_wrap2_getdata");
 1339 
 1340     /* Either send or get data, not both. olympus_cmd is NULL now */
 1341     params->olympus_cmd = generate_xml (params, ptp, NULL, 0);
 1342 
 1343     /* Do the fun stuff. */
 1344     ret = olympus_xml_transfer (params, params->olympus_cmd, &resxml);
 1345     if (ret != PTP_RC_OK)
 1346         return ret;
 1347 
 1348     /* Remember the returned XML for getresp() for the PTP return code. */
 1349     params->olympus_reply = resxml;
 1350     switch (ptp->Code) {
 1351 #if 0
 1352     case PTP_OC_GetDevicePropDesc: {
 1353         PTPPropertyDesc dpd;
 1354         parse_9301_propdesc (xmlFirstElementChild (next), &dpd);
 1355         /* decode the XML ... reencode the binary presentation of the propdesc */
 1356         break;
 1357     }
 1358 #endif
 1359     default:
 1360         /* Just put the XML blob as-is as data... It will be processed in ptp.c */
 1361         return putter->putfunc(params,putter->priv,strlen(resxml)+1,(unsigned char*)resxml);
 1362     }
 1363 }
 1364 
 1365 static uint16_t
 1366 ums_wrap2_getresp (PTPParams* params, PTPContainer* resp) {
 1367     int ret;
 1368 
 1369     if (is_outer_operation(params, resp->Code))
 1370         return ums_wrap_getresp (params, resp);
 1371 
 1372     GP_LOG_D ("ums_wrap2_getresp");
 1373     if (!params->olympus_cmd) /* no data phase at all */
 1374         params->olympus_cmd = generate_xml (params, resp, NULL, 0);
 1375     if (!params->olympus_reply) {
 1376         /* Do the actual handshake here. */
 1377         ret = olympus_xml_transfer (params, params->olympus_cmd, &params->olympus_reply);
 1378         if (ret != PTP_RC_OK) {
 1379             GP_LOG_E ("ums_wrap2_getresp: error %x from transfer", ret);
 1380             return ret;
 1381         }
 1382     }
 1383     parse_xml (params, params->olympus_reply, resp);
 1384     return PTP_RC_OK;
 1385 }
 1386 
 1387 uint16_t
 1388 olympus_setup (PTPParams *params) {
 1389     PTPParams   *outerparams;
 1390 
 1391     params->getresp_func    = ums_wrap2_getresp;
 1392     params->senddata_func   = ums_wrap2_senddata;
 1393     params->getdata_func    = ums_wrap2_getdata;
 1394     params->sendreq_func    = ums_wrap2_sendreq;
 1395 
 1396     params->event_check = ums_wrap2_event_check;
 1397     params->event_wait  = ums_wrap2_event_check;
 1398 
 1399     params->outer_params = outerparams = malloc (sizeof(PTPParams));
 1400     memcpy(outerparams, params, sizeof(PTPParams));
 1401     outerparams->sendreq_func   = ums_wrap_sendreq;
 1402     outerparams->getresp_func   = ums_wrap_getresp;
 1403     outerparams->senddata_func  = ums_wrap_senddata;
 1404     outerparams->getdata_func   = ums_wrap_getdata;
 1405     outerparams->getdata_func   = ums_wrap_getdata;
 1406 
 1407     /* events come just as PTP events */
 1408     outerparams->event_check    = ptp_usb_event_check;
 1409     outerparams->event_wait     = ptp_usb_event_wait;
 1410 
 1411     return PTP_RC_OK;
 1412 }
 1413 #endif /* HAVE_LIBXML2 */