In order to write proper MH config files, we needed to be able to write zip
files; thus libzzip was replaced with libzip.

Signed-off-by: Scott Talbert <s...@techie.net>
---
Changes in v3: removed all uses of libzzip and replaced with libzip; switched
to use new ReadFile function which eliminated a lot of duplicated code.
v4: fixed a whitespace error (which predated this patch!)

 libconcord/INSTALL.linux     |  4 +-
 libconcord/INSTALL.mac       |  2 +-
 libconcord/Makefile.am       |  2 +-
 libconcord/configure.ac      |  6 +--
 libconcord/libconcord.cpp    | 89 +++++++++++++++++++++++++++++++++++++++++++-
 libconcord/operationfile.cpp | 44 ++++++++++------------
 libconcord/remote.h          |  2 +
 libconcord/remote_mh.cpp     | 72 +++++++++++++++++++++++++++++++++--
 libconcord/xml_headers.h     |  1 +
 9 files changed, 187 insertions(+), 35 deletions(-)

diff --git a/libconcord/INSTALL.linux b/libconcord/INSTALL.linux
index 06a0385..7e622ed 100644
--- a/libconcord/INSTALL.linux
+++ b/libconcord/INSTALL.linux
@@ -7,14 +7,14 @@ source, see the instructions below.
 
 0. INSTALL REQUIRED SOFTWARE
 
-You *MUST* install libusb and libzzip. These libraries are in most
+You *MUST* install libusb and libzip. These libraries are in most
 distributions, so apt-get/yum/up2date/urpmi/etc. it.
 
 Also, if you are using 900/1000/1100 remotes, then dnsmasq is a requirement,
 as well as installing the udev support files for libconcord (see below).
 
 If you're compiling libconcord from source, you'll also need the development
-packages - usually libusb-dev or libusb-devel (and libzzip-dev/libzzip-devel),
+packages - usually libusb-dev or libusb-devel (and libzip-dev/libzip-devel),
 depending on your distribution.
 
 1. BUILD LIBCONCORD
diff --git a/libconcord/INSTALL.mac b/libconcord/INSTALL.mac
index 0c74b92..d69265f 100644
--- a/libconcord/INSTALL.mac
+++ b/libconcord/INSTALL.mac
@@ -30,7 +30,7 @@ that first. It is also straight forward:
    make
    sudo make install
 
-Finally, you will need to install libzzip, which again is straight forward:
+Finally, you will need to install libzip, which again is straight forward:
    ./configure --prefix=/usr
    make
    sudo make install
diff --git a/libconcord/Makefile.am b/libconcord/Makefile.am
index 808484c..79182a9 100644
--- a/libconcord/Makefile.am
+++ b/libconcord/Makefile.am
@@ -6,7 +6,7 @@ libconcord_la_SOURCES = remote.cpp remote_z.cpp libconcord.cpp 
binaryfile.cpp \
     remote_info.h web.h protocol.h remote.h usblan.h xml_headers.h \
     operationfile.cpp remote_mh.cpp
 include_HEADERS = libconcord.h
-libconcord_la_LDFLAGS = -version-info 3:0:0 -lusb -lzzip
+libconcord_la_LDFLAGS = -version-info 3:0:0 -lusb -lzip
 UDEVROOT ?= /
 UDEVLIBDIR ?= $(UDEVROOT)/lib
 
diff --git a/libconcord/configure.ac b/libconcord/configure.ac
index bd0477d..51107ef 100644
--- a/libconcord/configure.ac
+++ b/libconcord/configure.ac
@@ -28,11 +28,11 @@ if test $a == 0
 then
        AC_MSG_ERROR([Error, libusb is missing!])
 fi
-AC_CHECK_HEADER(zzip/lib.h, [], [a=0])
-AC_CHECK_LIB(zzip, zzip_dir_open, [], [a=0])
+AC_CHECK_HEADER(zip.h, [], [a=0])
+AC_CHECK_LIB(zip, zip_open, [], [a=0])
 if test $a == 0
 then
-       AC_MSG_ERROR([Error, libzzip is missing!])
+       AC_MSG_ERROR([Error, libzip is missing!])
 fi
 AC_CONFIG_HEADERS([config.h])
 AC_CONFIG_FILES([
diff --git a/libconcord/libconcord.cpp b/libconcord/libconcord.cpp
index 82b3afe..99c3ae3 100644
--- a/libconcord/libconcord.cpp
+++ b/libconcord/libconcord.cpp
@@ -29,7 +29,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
-#include <zzip/lib.h>
+#include <zip.h>
 #include <list>
 #ifndef WIN32
 #include <unistd.h>
@@ -1043,6 +1043,82 @@ int _write_config_to_remote(lc_callback cb, void 
*cb_arg, uint32_t cb_stage)
     return 0;
 }
 
+/*
+ * When MH configs are read from the remote, sometimes the remote returns extra
+ * data after the end of the config file proper.  This function searches for
+ * the sequence of bytes that indicates the end of the config and returns the
+ * real length of the config that should be written out to disk.
+ */
+uint32_t _mh_get_config_len(uint8_t *in, uint32_t size)
+{
+    for (int i = 0; (i + 3) < size; i++) {
+        if (!memcmp(&in[i], MH_EOF_BYTES, 4)) {
+            return i + 4;
+        }
+    }
+    debug("Failed to find MH config EOF sequence");
+    return 0;
+}
+
+int _mh_write_config_to_file(uint8_t *in, uint32_t size, char *file_name)
+{
+    int zip_err;
+    struct zip *zip = zip_open(file_name, ZIP_CREATE | ZIP_EXCL, &zip_err);
+    if (!zip) {
+        if (zip_err == ZIP_ER_EXISTS) {
+            printf("Error: file %s already exists\n", file_name);
+        } else {
+            debug("Failed to create zip file %s", file_name);
+        }
+        return LC_ERROR_OS_FILE;
+    }
+    int index;
+
+    // Write XML
+    extern const char *mh_config_header;
+    int xml_buffer_len = strlen(mh_config_header) + 100;
+    char *xml_buffer = new char[xml_buffer_len];
+    uint16_t checksum = mh_get_checksum(in, size);
+    int xml_len = snprintf(xml_buffer, xml_buffer_len, mh_config_header,
+        size, size - 6, checksum, ri.skin);
+    if (xml_len >= xml_buffer_len) {
+        debug("Error, XML buffer length exceeded");
+        return LC_ERROR;
+    }
+    struct zip_source *xml = zip_source_buffer(zip, xml_buffer, xml_len, 0);
+    if (!xml) {
+        debug("Failed to create zip_source_buffer for XML file");
+        return LC_ERROR_OS_FILE;
+    }
+    index = zip_add(zip, "Description.xml", xml);
+    if (index == -1) {
+        debug("Error writing XML to zip file");
+        zip_source_free(xml);
+        return LC_ERROR_OS_FILE;
+    }
+
+    // Write EzHex file
+    struct zip_source *ezhex = zip_source_buffer(zip, in, size, 0);
+    if (!ezhex) {
+        debug("Failed to create zip_source_buffer for EzHex file");
+        return LC_ERROR_OS_FILE;
+    }
+    index = zip_add(zip, "Result.EzHex", ezhex);
+    if (index == -1) {
+        debug("Error writing EzHex to zip file");
+        zip_source_free(ezhex);
+        return LC_ERROR_OS_FILE;
+    }
+
+    if (zip_close(zip) != 0) {
+        debug("Error closing zip file");
+        return LC_ERROR_OS_FILE;
+    }
+
+    delete[] xml_buffer;
+    return 0;
+}
+
 int write_config_to_remote(lc_callback cb, void *cb_arg)
 {
     return _write_config_to_remote(cb, cb_arg, LC_CB_STAGE_WRITE_CONFIG);
@@ -1051,6 +1127,17 @@ int write_config_to_remote(lc_callback cb, void *cb_arg)
 int write_config_to_file(uint8_t *in, uint32_t size, char *file_name,
     int binary)
 {
+    // If this is an MH remote, need to find the real end of the binary
+    if (is_mh_remote()) {
+        size = _mh_get_config_len(in, size);
+        ri.config_bytes_used = size;
+    }
+
+    // If this is an MH remote, need to write out zip file with XML/binary
+    if (!binary && is_mh_remote()) {
+        return _mh_write_config_to_file(in, size, file_name);
+    }
+
     binaryoutfile of;
 
     if (of.open(file_name) != 0) {
diff --git a/libconcord/operationfile.cpp b/libconcord/operationfile.cpp
index df5f176..bb2c6ee 100644
--- a/libconcord/operationfile.cpp
+++ b/libconcord/operationfile.cpp
@@ -22,7 +22,7 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <zzip/lib.h>
+#include <zip.h>
 #include <string>
 
 #include "libconcord.h"
@@ -88,39 +88,35 @@ int find_config_binary(uint8_t *config, uint32_t 
config_size,
 int OperationFile::ReadZipFile(char *file_name)
 {
     /* TODO: error checking */
-    zzip_error_t zip_err;
-    ZZIP_DIR *dir = zzip_dir_open(file_name, &zip_err);
-    if (dir) {
-        ZZIP_DIRENT dirent;
-        while (zzip_dir_read(dir, &dirent)) {
-            ZZIP_FILE *fh = zzip_file_open(dir, dirent.d_name, 0);
-            if ((strcmp(dirent.d_name, "Data.xml") == 0) || 
-                (strcmp(dirent.d_name, "Description.xml") == 0)) {
-                debug("Internal file is %s", dirent.d_name);
-                debug("Size is %d", dirent.st_size);
-                xml_size = dirent.st_size;
+    struct zip *zip = zip_open(file_name, 0, NULL);
+    if (zip) {
+        struct zip_stat stat;
+        zip_uint64_t num_entries = zip_get_num_entries(zip, 0);
+        for (zip_uint64_t i = 0; i < num_entries; i++) {
+            zip_stat_index(zip, i, 0, &stat);
+            struct zip_file *file = zip_fopen(zip, stat.name, 0);
+            if ((strcmp(stat.name, "Data.xml") == 0) ||
+                (strcmp(stat.name, "Description.xml") == 0)) {
+                debug("Internal file is %s", stat.name);
+                debug("Size is %d", stat.size);
+                xml_size = stat.size;
                 xml = new uint8_t[xml_size];
-                zzip_size_t len = zzip_file_read(fh, xml,
+                int len = zip_fread(file, xml, xml_size);
+                debug("len is %d, xml is %p, and xmlsize is %d", len, xml,
                     xml_size);
-                debug("ERR IS: %s, len was %d",
-                    zzip_strerror_of(dir), len);
-                debug("xml is %d and xmlsize is %d", xml,
-                    xml_size);
-                //debug("%s%s%s%s", xml[0], xml[1], xml[2],
-                //    xml[3]);
             } else {
-                data_size = dirent.st_size;
+                data_size = stat.size;
                 data = new uint8_t[data_size];
                 data_alloc = true;
-                zzip_size_t len = zzip_file_read(fh, data,
-                    data_size);
+                int len = zip_fread(file, data, data_size);
+                debug("len is %d, data_size is %d", len, data_size);
             }
-            zzip_file_close(fh);
+            zip_fclose(file);
         }
     } else {
         return LC_ERROR;
     }
-    zzip_dir_close(dir);
+    zip_close(zip);
     return 0;
 }
 
diff --git a/libconcord/remote.h b/libconcord/remote.h
index 44412cf..5d835ab 100644
--- a/libconcord/remote.h
+++ b/libconcord/remote.h
@@ -35,6 +35,7 @@
    which is 1 (num params) + 3 (3 parameter size bytes) + 1 (param 1)
    + 1024 (param 2) + 4 (param 3) = 1033. */
 #define USBNET_MAX_PACKET_SIZE 1033
+const uint8_t MH_EOF_BYTES[] = { 0x50, 0x54, 0x59, 0x59 };
 
 /*
  * limits for IR signal learning, stop when any is reached:
@@ -151,6 +152,7 @@ void setup_ri_pointers(TRemoteInfo &ri);
 void make_serial(uint8_t *ser, TRemoteInfo &ri);
 int LearnIRInnerLoop(uint32_t *freq, uint32_t **ir_signal,
     uint32_t *ir_signal_length, uint8_t seq);
+uint16_t mh_get_checksum(uint8_t* rd, const uint32_t len);
 
 class CRemoteBase            // Base class for all remotes
 {
diff --git a/libconcord/remote_mh.cpp b/libconcord/remote_mh.cpp
index c6b0ca0..ef5b040 100644
--- a/libconcord/remote_mh.cpp
+++ b/libconcord/remote_mh.cpp
@@ -492,8 +492,29 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO &hid, 
lc_callback cb,
         cb(cb_stage, cb_count++, 1, 2, LC_CB_COUNTER_TYPE_STEPS, cb_arg, NULL);
     }
 
-    ri.config_bytes_used = 0;
-    ri.max_config_size = 1;
+    // Send the read config message to find the config bytes used.
+    const uint8_t msg_read_config[MH_MAX_PACKET_SIZE] =
+        { 0xFF, 0x01, 0x00, 0x03, 0x80, '/', 'c', 'f', 'g', '/',
+          'u', 's', 'e', 'r', 'c', 'f', 'g', 0x00, 0x80, 'R', 0x00 };
+    if ((err = HID_WriteReport(msg_read_config))) {
+        debug("Failed to write to remote");
+        return LC_ERROR_WRITE;
+    }
+
+    if ((err = HID_ReadReport(rsp))) {
+        debug("Failed to read from remote");
+        return LC_ERROR_READ;
+    }
+    debug("msg_read_config");
+    debug_print_packet(rsp);
+
+    // There are four extra bytes at the end of every MH config file -
+    // we add an extra four here so there is space in ReadFlash() to add
+    // those bytes.
+    ri.config_bytes_used = (rsp[7] << 24) + (rsp[8] << 16) + (rsp[9] << 8)
+        + rsp[10] + 4;
+    debug("ri.config_bytes_used = %d", ri.config_bytes_used);
+    ri.max_config_size = (ri.flash->size << 10);
     ri.valid_config = 1;
 
     if (cb) {
@@ -515,14 +536,59 @@ int CRemoteMH::GetIdentity(TRemoteInfo &ri, THIDINFO 
&hid, lc_callback cb,
         make_serial(guid, ri);
     }
 
+    /* reset the sequence number to 0 */
+    const uint8_t msg_reset_seq[MH_MAX_PACKET_SIZE] =
+        { 0xFF, 0x07, 0x01, 0x01, 0x01, 0x06 };
+    if ((err = HID_WriteReport(msg_reset_seq))) {
+        debug("Failed to write to remote");
+        return LC_ERROR_WRITE;
+    }
+
+    if ((err = HID_ReadReport(rsp))) {
+        debug("Failed to read from remote");
+        return LC_ERROR_READ;
+    }
+    debug("msg_reset_seq");
+    debug_print_packet(rsp);
+
     return 0;
 }
 
+// Calculates the XOR checksum for a config read from the remote.
+uint16_t mh_get_checksum(uint8_t* rd, const uint32_t len)
+{
+    // This is the "SEED" that all the configs from the website use.
+    uint16_t cksum = 0x4321;
+    // The part of the config that gets checksummed is consistently 6 bytes
+    // less than the length of the config.  Since we are checksumming two
+    // bytes at a time, we stop when i == len - 7, which is the same as
+    // i + 1 == len - 6.  In the case of odd lengths, we skip the last byte.
+    for (int i = 0; i < (len - 7); i += 2) {
+        uint16_t j = (rd[i+1] << 8) + rd[i];
+        cksum ^= j;
+    }
+    debug("CHECKSUM=0x%04x", cksum);
+    return cksum;
+}
+
 int CRemoteMH::ReadFlash(uint32_t addr, const uint32_t len, uint8_t *rd,
                          unsigned int protocol, bool verify, lc_callback cb,
                          void *cb_arg, uint32_t cb_stage)
 {
-    return LC_ERROR_UNSUPP;
+    int err = 0;
+    int data_read;
+
+    if (err = ReadFile("/cfg/usercfg", rd, len, &data_read, 0x00))
+        return err;
+
+    /*
+     * There are four extra bytes at the end of every config file, but they
+     * are not present when read from the remote.  Add them here.
+     */
+    if (rd)
+        memcpy(rd + len - 4, MH_EOF_BYTES, 4);
+
+    return 0;
 }
 
 int CRemoteMH::InvalidateFlash(lc_callback cb, void *cb_arg, uint32_t lc_stage)
diff --git a/libconcord/xml_headers.h b/libconcord/xml_headers.h
index aa2d663..6f79253 100644
--- a/libconcord/xml_headers.h
+++ b/libconcord/xml_headers.h
@@ -129,6 +129,7 @@ const char *config_header="\
 </INFORMATION>\r\n";
 
 
+const char *mh_config_header = "<DATA><FILES><FILE NAME=\"Result.EzHex\" 
SIZE=\"%i\" PATH=\"/cfg/usercfg\" VERSION=\"1\" FW_VERSION=\"9.5\" 
OPERATIONTYPE=\"userconfiguration\"><CHECKSUM SEED=\"0x4321\" OFFSET=\"0x0\" 
LENGTH=\"0x%04x\" EXPECTEDVALUE=\"0x%04x\" 
TYPE=\"XOR\"/></FILE></FILES><INTENDED><SKIN>%i</SKIN></INTENDED><ORDER><ORDER_ELEMENT
 NAME=\"Result.EzHex\" RESET=\"true\"/></ORDER></DATA>";
 
 //User-Agent: HarmonyBrowser/7.7.0 (Build 0; UpdatedFrom 7.3.0.15; Skin 
logitech; Windows Vista 6.1; x86; en; rv: 1.8.0.2) Gecko/20060125\r\n\
 
-- 
1.8.3.1


------------------------------------------------------------------------------
LIMITED TIME SALE - Full Year of Microsoft Training For Just $49.99!
1,500+ hours of tutorials including VisualStudio 2012, Windows 8, SharePoint
2013, SQL 2012, MVC 4, more. BEST VALUE: New Multi-Library Power Pack includes
Mobile, Cloud, Java, and UX Design. Lowest price ever! Ends 9/22/13. 
http://pubads.g.doubleclick.net/gampad/clk?id=64545871&iu=/4140/ostg.clktrk
_______________________________________________
concordance-devel mailing list
concordance-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/concordance-devel

Reply via email to