From 1b784dbb9f1bdbb6aca2b21e5ef5942ea3ff7225 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sun, 3 Feb 2019 01:13:23 +0800 Subject: [PATCH] [2.7] bpo-1104: msilib.SummaryInfo.GetProperty() truncates the string by one character (GH-4517) Add one char to MsiSummaryInfoGetProperty() output Based on the patch in bpo-1104 by Anthony Tuininga (atuining) and Mark McMahon (markm).. (cherry picked from commit 2de576e16d42ce43698d384d0dd46ba6cf165424) Co-authored-by: Tzu-ping Chung --- Lib/test/test_msilib.py | 47 +++++++++++++++++-- .../2017-11-24-12-53-54.bpo-1104.1CWSZp.rst | 2 + PC/_msi.c | 31 ++++++++---- 3 files changed, 67 insertions(+), 13 deletions(-) create mode 100644 Misc/NEWS.d/next/Windows/2017-11-24-12-53-54.bpo-1104.1CWSZp.rst diff --git a/Lib/test/test_msilib.py b/Lib/test/test_msilib.py index 5d5b0c48fea6f6..a2f3943e228119 100644 --- a/Lib/test/test_msilib.py +++ b/Lib/test/test_msilib.py @@ -1,8 +1,48 @@ """ Test suite for the code in msilib """ import unittest -import os -from test_support import run_unittest, import_module +from test_support import TESTFN, import_module, run_unittest, unlink msilib = import_module('msilib') +import msilib.schema + + +def init_database(): + path = TESTFN + '.msi' + db = msilib.init_database( + path, + msilib.schema, + 'Python Tests', + 'product_code', + '1.0', + 'PSF', + ) + return db, path + + +class MsiDatabaseTestCase(unittest.TestCase): + + def test_summaryinfo_getproperty_issue1104(self): + db, db_path = init_database() + try: + sum_info = db.GetSummaryInformation(99) + title = sum_info.GetProperty(msilib.PID_TITLE) + self.assertEqual(title, b"Installation Database") + + sum_info.SetProperty(msilib.PID_TITLE, "a" * 999) + title = sum_info.GetProperty(msilib.PID_TITLE) + self.assertEqual(title, b"a" * 999) + + sum_info.SetProperty(msilib.PID_TITLE, "a" * 1000) + title = sum_info.GetProperty(msilib.PID_TITLE) + self.assertEqual(title, b"a" * 1000) + + sum_info.SetProperty(msilib.PID_TITLE, "a" * 1001) + title = sum_info.GetProperty(msilib.PID_TITLE) + self.assertEqual(title, b"a" * 1001) + finally: + db = None + sum_info = None + unlink(db_path) + class Test_make_id(unittest.TestCase): #http://msdn.microsoft.com/en-us/library/aa369212(v=vs.85).aspx @@ -35,12 +75,13 @@ def test_invalid_first_char(self): def test_invalid_any_char(self): self.assertEqual( msilib.make_id(".s\x82ort"), "_.s_ort") - self.assertEqual ( + self.assertEqual( msilib.make_id(".s\x82o?*+rt"), "_.s_o___rt") def test_main(): run_unittest(__name__) + if __name__ == '__main__': test_main() diff --git a/Misc/NEWS.d/next/Windows/2017-11-24-12-53-54.bpo-1104.1CWSZp.rst b/Misc/NEWS.d/next/Windows/2017-11-24-12-53-54.bpo-1104.1CWSZp.rst new file mode 100644 index 00000000000000..a4043496bc2463 --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2017-11-24-12-53-54.bpo-1104.1CWSZp.rst @@ -0,0 +1,2 @@ +Correctly handle string length in ``msilib.SummaryInfo.GetProperty()`` to +prevent it from truncating the last character. diff --git a/PC/_msi.c b/PC/_msi.c index 68c4e79e294549..4000f00c763bc3 100644 --- a/PC/_msi.c +++ b/PC/_msi.c @@ -539,7 +539,7 @@ summary_getproperty(msiobj* si, PyObject *args) FILETIME fval; char sbuf[1000]; char *sval = sbuf; - DWORD ssize = sizeof(sval); + DWORD ssize = sizeof(sbuf); if (!PyArg_ParseTuple(args, "i:GetProperty", &field)) return NULL; @@ -547,6 +547,7 @@ summary_getproperty(msiobj* si, PyObject *args) status = MsiSummaryInfoGetProperty(si->h, field, &type, &ival, &fval, sval, &ssize); if (status == ERROR_MORE_DATA) { + ssize++; sval = malloc(ssize); if (sval == NULL) { return PyErr_NoMemory(); @@ -556,19 +557,29 @@ summary_getproperty(msiobj* si, PyObject *args) } switch(type) { - case VT_I2: case VT_I4: - return PyInt_FromLong(ival); + case VT_I2: + case VT_I4: + result = PyLong_FromLong(ival); + break; case VT_FILETIME: PyErr_SetString(PyExc_NotImplementedError, "FILETIME result"); - return NULL; + result = NULL; + break; case VT_LPSTR: - result = PyString_FromStringAndSize(sval, ssize); - if (sval != sbuf) - free(sval); - return result; + result = PyBytes_FromStringAndSize(sval, ssize); + break; + case VT_EMPTY: + Py_INCREF(Py_None); + result = Py_None; + break; + default: + PyErr_Format(PyExc_NotImplementedError, "result of type %d", type); + result = NULL; + break; } - PyErr_Format(PyExc_NotImplementedError, "result of type %d", type); - return NULL; + if (sval != sbuf) + free(sval); + return result; } static PyObject*