The documentation files had incorrect file extensions. This is fixed in
the attached version.
On Do, 2015-11-05 at 10:36 +0000, Levermann, Simon wrote:
> Hi Brad,
>
> the attached patch limits lines to 79 cols, and adds the necessary
> documentation to the variables and release notes.
>
> I added diagnostic pragmas to suppress the deprecation warnings as
> well
> as a comment explaining the need for them. I've looked for a
> replacement some more, but I still haven't been able to find
> anything.
> I could try to hard-code it by writing a simple program that iterates
> all possible language codes (it's "only" a 16-bit value, so 2^16
> combinations). However, this feels even hackier to me than the
> current
> state.
>
> This patch is a single commit rebased on current master
> (60cbd9b9da2059481e2f29fbb5859a5b0643d3d7)
>
> Kind regards,
> Simon
>
> On Mi, 2015-11-04 at 10:46 -0500, Brad King wrote:
> > On 11/03/2015 06:09 AM, Levermann, Simon wrote:
> > > This adds support for multilingual SLAs which are displayed when
> > > the user is trying to mount the DMG.
> >
> > Thanks for working on this and for bringing the patch to this list.
> >
> > Patches 2 and 3 look like fixups. Please squash that all into one
> > commit. Also please keep C++ sources wrapped to 79 columns or
> > less.
> >
> > > Multiple languages can be added via the new variables
> > > CPACK_DMG_SLA_DIR
> > > and CPACK_DMG_SLA_LANGUAGES.
> >
> > Please add Help/variable/*.rst files to document these. Also
> > please add a Help/release/dev/*.rst file to add a release note
> > for the feature.
> >
> > > For each language defined, CPack will search for a
> > > language.menu.txt
> > > and language.license.txt file in CPACK_SLA_DIR.
> >
> > Good. Please mention this in the above-requested documentation.
> >
> > > This patch adds a library to the deprecated Carbon Framework to
> > > CPackLib, since the functions/types required to acquire the
> > > region
> > > code for the internal LPic data structure are only available in
> > > this
> > > old API. Apple does not seem to be offering a replacement API for
> > > the
> > > old ScriptManager region codes.
> >
> > Hopefully an alternative can be found. Meanwhile I get warnings
> > during the build due to
> > DEPRECATED_IN_MAC_OS_X_VERSION_10_6_AND_LATER
> > appearing on the declarations of these APIs. Please add pragmas
> > or whatever is needed to suppress them, at least with Clang. Call
> > out the purpose for the suppression with a comment explaining why
> > we need to use the deprecated APIs.
> >
> > > Additional thought: One could add the language.menu.txt files for
> > > some common languages to the repository.
> >
> > Let's defer that until the actual feature is working.
> >
> > Thanks,
> > -Brad
> --
>
> Powered by www.kitware.com
>
> Please keep messages on-topic and check the CMake FAQ at:
> http://www.cmake.org/Wiki/CMake_FAQ
>
> Kitware offers various services to support the CMake community. For
> more information on each offering, please visit:
>
> CMake Support: http://cmake.org/cmake/help/support.html
> CMake Consulting: http://cmake.org/cmake/help/consulting.html
> CMake Training Courses: http://cmake.org/cmake/help/training.html
>
> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>
> Follow this link to subscribe/unsubscribe:
> http://public.kitware.com/mailman/listinfo/cmake-developers
From 8191397c2da9d0698b37b86ddc1c2ca69bc48c72 Mon Sep 17 00:00:00 2001
From: Simon Levermann <simon-git...@slevermann.de>
Date: Mon, 19 Oct 2015 11:13:55 +0200
Subject: [PATCH] Add support for multilingual SLAs
Multiple languages for SLAs and the SLA UI can be added via the CPack variables
CPACK_DMG_SLA_DIR and CPACK_DMG_SLA_LANGUAGES. For each language defined in the
languages variable, CPack will search for <language>.menu.txt and
<language>.license.txt in CPACK_DMG_SLA_DIR. If the sla directory variable is not
defined, the old behaviour using CPACK_RESOURCE_FILE_LICENSE is retained
Pass string by const& instead of copying
Remove superfluous assignment
Add deprecation pragma and comment
Break lines longer than 79 characters
Add variable documentation for new CPACK_DMG_ variables
Add release note for multilanguage-sla
---
Help/release/dev/cpack-dmg-multilanguage-sla.rst | 6 +
Help/variable/CPACK_DMG_SLA_DIR.rst | 6 +
Help/variable/CPACK_DMG_SLA_LANGUAGES.rst | 6 +
Source/CMakeLists.txt | 4 +
Source/CPack/cmCPackDragNDropGenerator.cxx | 357 ++++++++++++++++++++---
Source/CPack/cmCPackDragNDropGenerator.h | 10 +
6 files changed, 351 insertions(+), 38 deletions(-)
create mode 100644 Help/release/dev/cpack-dmg-multilanguage-sla.rst
create mode 100644 Help/variable/CPACK_DMG_SLA_DIR.rst
create mode 100644 Help/variable/CPACK_DMG_SLA_LANGUAGES.rst
diff --git a/Help/release/dev/cpack-dmg-multilanguage-sla.rst b/Help/release/dev/cpack-dmg-multilanguage-sla.rst
new file mode 100644
index 0000000..cdf3162
--- /dev/null
+++ b/Help/release/dev/cpack-dmg-multilanguage-sla.rst
@@ -0,0 +1,6 @@
+cpack-dmg-multilanguage-sla
+--------------
+
+* This feature adds the capability to add multi-lingual SLAs to a DMG which
+ is presented to the user when they try to mount the DMG. See :variable:`CPACK_DMG_SLA_LANGUAGES`
+ and :variable:`CPACK_DMG_SLA_DIR` for usage information.
diff --git a/Help/variable/CPACK_DMG_SLA_DIR.rst b/Help/variable/CPACK_DMG_SLA_DIR.rst
new file mode 100644
index 0000000..7b38a23
--- /dev/null
+++ b/Help/variable/CPACK_DMG_SLA_DIR.rst
@@ -0,0 +1,6 @@
+CPACK_DMG_SLA_DIR
+--------------------
+
+Directory where license and menu files for different languages are stored
+
+See :variable:`CPACK_DMG_SLA_LANGUAGES` for more information.
diff --git a/Help/variable/CPACK_DMG_SLA_LANGUAGES.rst b/Help/variable/CPACK_DMG_SLA_LANGUAGES.rst
new file mode 100644
index 0000000..77eef61
--- /dev/null
+++ b/Help/variable/CPACK_DMG_SLA_LANGUAGES.rst
@@ -0,0 +1,6 @@
+CPACK_DMG_SLA_LANGUAGES
+--------------------
+
+Languages for which a license agreement is provided when mounting the generated DMG.
+
+For every language in this list, CPack will try to find a file language.menu.txt and language.license.txt in :variable:`CPACK_DMG_SLA_DIR`.
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index fd71b0e..729f6ab 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -726,6 +726,10 @@ endif()
# Build CPackLib
add_library(CPackLib ${CPACK_SRCS})
target_link_libraries(CPackLib CMakeLib)
+if(APPLE)
+ include_directories (${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Carbon.framework/Headers/)
+ target_link_libraries(CPackLib "-framework Carbon")
+endif()
if(APPLE)
add_executable(cmakexbuild cmakexbuild.cxx)
diff --git a/Source/CPack/cmCPackDragNDropGenerator.cxx b/Source/CPack/cmCPackDragNDropGenerator.cxx
index 4c400d9..993a571 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.cxx
+++ b/Source/CPack/cmCPackDragNDropGenerator.cxx
@@ -18,6 +18,20 @@
#include <cmsys/RegularExpression.hxx>
#include <cmsys/FStream.hxx>
+#include <iomanip>
+
+#include <CoreFoundation/CFBase.h>
+#include <CoreFoundation/CFString.h>
+#include <CoreFoundation/CFLocale.h>
+
+// The carbon framework is deprecated, but the Region codes it supplies are
+// needed for the LPic data structure used for generating multi-lingual SLAs.
+// There does not seem to be a replacement API for these region codes.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+#include <Carbon.h>
+#pragma clang diagnostic pop
+
static const char* SLAHeader =
"data 'LPic' (5000) {\n"
" $\"0002 0011 0003 0001 0000 0000 0002 0000\"\n"
@@ -103,6 +117,70 @@ int cmCPackDragNDropGenerator::InitializeInternal()
}
this->SetOptionIfNotSet("CPACK_COMMAND_REZ", rez_path.c_str());
+ if(this->IsSet("CPACK_DMG_SLA_DIR"))
+ {
+ slaDirectory = this->GetOption("CPACK_DMG_SLA_DIR");
+ if(!slaDirectory.empty() && this->IsSet("CPACK_RESOURCE_FILE_LICENSE"))
+ {
+ std::string license_file =
+ this->GetOption("CPACK_RESOURCE_FILE_LICENSE");
+ if(!license_file.empty() &&
+ (license_file.find("CPack.GenericLicense.txt") == std::string::npos))
+ {
+ cmCPackLogger(cmCPackLog::LOG_WARNING,
+ "Both CPACK_DMG_SLA_DIR and CPACK_RESOURCE_FILE_LICENSE specified, "
+ "defaulting to CPACK_DMG_SLA_DIR"
+ << std::endl);
+ }
+ }
+ if(!this->IsSet("CPACK_DMG_LANGUAGES"))
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_DIR set but no languages defined "
+ "(set CPACK_DMG_LANGUAGES)"
+ << std::endl);
+ return 0;
+ }
+ if(!cmSystemTools::FileExists(slaDirectory, false))
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_SLA_DIR does not exist"
+ << std::endl);
+ return 0;
+ }
+
+ std::vector<std::string> languages;
+ cmSystemTools::ExpandListArgument(this->GetOption("CPACK_DMG_LANGUAGES"),
+ languages);
+ if(languages.empty())
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "CPACK_DMG_LANGUAGES set but empty"
+ << std::endl);
+ return 0;
+ }
+ for(size_t i = 0; i < languages.size(); ++i)
+ {
+ std::string license = slaDirectory + "/" + languages[i] +
+ ".license.txt";
+ if (!cmSystemTools::FileExists(license))
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Missing license file " << languages[i] << ".license.txt"
+ << std::endl);
+ return 0;
+ }
+ std::string menu = slaDirectory + "/" + languages[i] + ".menu.txt";
+ if (!cmSystemTools::FileExists(menu))
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Missing menu file " << languages[i] << ".menu.txt"
+ << std::endl);
+ return 0;
+ }
+ }
+ }
+
return this->Superclass::InitializeInternal();
}
@@ -246,9 +324,21 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
this->GetOption("CPACK_DMG_DS_STORE")
? this->GetOption("CPACK_DMG_DS_STORE") : "";
+ const std::string cpack_dmg_languages =
+ this->GetOption("CPACK_DMG_LANGUAGES")
+ ? this->GetOption("CPACK_DMG_LANGUAGES") : "";
+
// only put license on dmg if is user provided
if(!cpack_license_file.empty() &&
- cpack_license_file.find("CPack.GenericLicense.txt") != std::string::npos)
+ cpack_license_file.find("CPack.GenericLicense.txt")
+ != std::string::npos)
+ {
+ cpack_license_file = "";
+ }
+
+ // use sla_dir if both sla_dir and license_file are set
+ if(!cpack_license_file.empty() &&
+ !slaDirectory.empty())
{
cpack_license_file = "";
}
@@ -418,55 +508,123 @@ int cmCPackDragNDropGenerator::CreateDMG(const std::string& src_dir,
}
}
- if(!cpack_license_file.empty())
+ if(!cpack_license_file.empty() || !slaDirectory.empty())
{
+ // Use old hardcoded style if sla_dir is not set
+ bool oldStyle = slaDirectory.empty();
std::string sla_r = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
sla_r += "/sla.r";
- cmsys::ifstream ifs;
- ifs.open(cpack_license_file.c_str());
- if(ifs.is_open())
+ std::vector<std::string> languages;
+ if(!oldStyle)
{
- cmGeneratedFileStream osf(sla_r.c_str());
- osf << "#include <CoreServices/CoreServices.r>\n\n";
- osf << SLAHeader;
- osf << "\n";
- osf << "data 'TEXT' (5002, \"English\") {\n";
- while(ifs.good())
+ cmSystemTools::ExpandListArgument(cpack_dmg_languages, languages);
+ }
+
+ cmGeneratedFileStream ofs(sla_r.c_str());
+ ofs << "#include <CoreServices/CoreServices.r>\n\n";
+ if(oldStyle)
+ {
+ ofs << SLAHeader;
+ ofs << "\n";
+ }
+ else
+ {
+ /*
+ * LPic Layout
+ * (https://github.com/pypt/dmg-add-license/blob/master/main.c)
+ * as far as I can tell (no official documentation seems to exist):
+ * struct LPic {
+ * uint16_t default_language; // points to a resid, defaulting to 0,
+ * // which is the first set language
+ * uint16_t length;
+ * struct {
+ * uint16_t language_code;
+ * uint16_t resid;
+ * uint16_t encoding; // Encoding from TextCommon.h,
+ * // forcing MacRoman (0) for now. Might need to
+ * // allow overwrite per license by user later
+ * } item[1];
+ * }
+ */
+
+ // Create vector first for readability, then iterate to write to ofs
+ std::vector<std::uint16_t> header_data;
+ header_data.push_back(0);
+ header_data.push_back(languages.size());
+ for(size_t i = 0; i < languages.size(); ++i)
{
- std::string line;
- std::getline(ifs, line);
- // escape quotes
- std::string::size_type pos = line.find('\"');
- while(pos != std::string::npos)
+ CFStringRef language_cfstring = CFStringCreateWithCString(NULL,
+ languages[i].c_str(), kCFStringEncodingUTF8);
+ CFStringRef iso_language =
+ CFLocaleCreateCanonicalLanguageIdentifierFromString(NULL,
+ language_cfstring);
+ if (!iso_language)
{
- line.replace(pos, 1, "\\\"");
- pos = line.find('\"', pos+2);
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ languages[i] << " is not a recognized language"
+ << std::endl);
}
- // break up long lines to avoid Rez errors
- std::vector<std::string> lines;
- const size_t max_line_length = 512;
- for(size_t i=0; i<line.size(); i+= max_line_length)
- {
- int line_length = max_line_length;
- if(i+max_line_length > line.size())
- line_length = line.size()-i;
- lines.push_back(line.substr(i, line_length));
- }
+ char *iso_language_cstr = (char *) malloc(65);
+ CFStringGetCString(iso_language, iso_language_cstr, 64,
+ kCFStringEncodingMacRoman);
+ LangCode lang = 0;
+ RegionCode region = 0;
+ OSStatus err = LocaleStringToLangAndRegionCodes(iso_language_cstr,
+ &lang, ®ion);
+ if (err != noErr)
+ {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "No language/region code available for " << iso_language_cstr
+ << std::endl);
+ free(iso_language_cstr);
+ return 0;
+ }
+ free(iso_language_cstr);
+ header_data.push_back(region);
+ header_data.push_back(i);
+ header_data.push_back(0);
+ }
+ ofs << "data 'LPic' (5000) {\n";
+ ofs << std::hex << std::uppercase << std::setfill('0');
- for(size_t i=0; i<lines.size(); i++)
- {
- osf << " \"" << lines[i] << "\"\n";
- }
- osf << " \"\\n\"\n";
+ for(size_t i = 0; i < header_data.size(); ++i)
+ {
+ if(i % 8 == 0)
+ {
+ ofs << " $\"";
+ }
+
+ ofs << std::setw(4) << header_data[i];
+
+ if(i % 8 == 7 || i == header_data.size() - 1)
+ {
+ ofs << "\"\n";
+ }
+ else
+ {
+ ofs << " ";
+ }
+ }
+ ofs << "};\n\n";
+ // Reset ofs options
+ ofs << std::dec << std::nouppercase << std::setfill(' ');
+ }
+
+ if(oldStyle)
+ {
+ WriteLicense(ofs, 0, "", cpack_license_file);
+ }
+ else
+ {
+ for(size_t i = 0; i < languages.size(); ++i)
+ {
+ WriteLicense(ofs, i + 5000, languages[i]);
}
- osf << "};\n";
- osf << "\n";
- osf << SLASTREnglish;
- ifs.close();
- osf.close();
}
+ ofs.Close();
+
// convert to UDCO
std::string temp_udco = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
temp_udco += "/temp-udco.dmg";
@@ -607,3 +765,126 @@ cmCPackDragNDropGenerator::GetComponentInstallDirNameSuffix(
return GetComponentPackageFileName(package_file_name, componentName, false);
}
+
+void
+cmCPackDragNDropGenerator::WriteLicense(cmGeneratedFileStream& outputStream,
+ int licenseNumber, std::string licenseLanguage, std::string licenseFile)
+{
+ if(!licenseFile.empty())
+ {
+ licenseNumber = 5002;
+ licenseLanguage = "English";
+ }
+
+ // License header
+ outputStream << "data 'TEXT' (" << licenseNumber << ", \""
+ << licenseLanguage << "\") {\n";
+ // License body
+ std::string actual_license = !licenseFile.empty() ? licenseFile :
+ (slaDirectory + "/" + licenseLanguage + ".license.txt");
+ cmsys::ifstream license_ifs;
+ license_ifs.open(actual_license);
+ if(license_ifs.is_open())
+ {
+ while(license_ifs.good())
+ {
+ std::string line;
+ std::getline(license_ifs, line);
+ if(!line.empty())
+ {
+ EscapeQuotes(line);
+ std::vector<std::string> lines;
+ BreakLongLine(line, lines);
+ for(size_t i = 0; i < lines.size(); ++i)
+ {
+ outputStream << " \"" << lines[i] << "\"\n";
+ }
+ }
+ outputStream << " \"\\n\"\n";
+ }
+ license_ifs.close();
+ }
+
+ // End of License
+ outputStream << "};\n\n";
+ if(!licenseFile.empty())
+ {
+ outputStream << SLASTREnglish;
+ }
+ else
+ {
+ // Menu header
+ outputStream << "resource 'STR#' (" << licenseNumber << ", \""
+ << licenseLanguage << "\") {\n";
+ outputStream << " {\n";
+
+ // Menu body
+ cmsys::ifstream menu_ifs;
+ menu_ifs.open(slaDirectory + "/" + licenseLanguage + ".menu.txt");
+ if(menu_ifs.is_open())
+ {
+ size_t lines_written = 0;
+ while(menu_ifs.good())
+ {
+ // Lines written from original file, not from broken up lines
+ std::string line;
+ std::getline(menu_ifs, line);
+ if(!line.empty())
+ {
+ EscapeQuotes(line);
+ std::vector<std::string> lines;
+ BreakLongLine(line, lines);
+ for(size_t i = 0; i < lines.size(); ++i)
+ {
+ std::string comma;
+ // We need a comma after every complete string,
+ // but not on the very last line
+ if(lines_written != 8 && i == lines.size() - 1)
+ {
+ comma = ",";
+ }
+ else
+ {
+ comma = "";
+ }
+ outputStream << " \"" << lines[i] << "\"" << comma << "\n";
+ }
+ ++lines_written;
+ }
+ }
+ menu_ifs.close();
+ }
+
+ //End of menu
+ outputStream << " }\n";
+ outputStream << "};\n";
+ outputStream << "\n";
+ }
+}
+
+void
+cmCPackDragNDropGenerator::BreakLongLine(const std::string& line,
+ std::vector<std::string>& lines)
+{
+ const size_t max_line_length = 512;
+ for(size_t i = 0; i < line.size(); i += max_line_length)
+ {
+ int line_length = max_line_length;
+ if(i + max_line_length > line.size())
+ {
+ line_length = line.size() - i;
+ }
+ lines.push_back(line.substr(i, line_length));
+ }
+}
+
+void
+cmCPackDragNDropGenerator::EscapeQuotes(std::string& line)
+{
+ std::string::size_type pos = line.find('\"');
+ while(pos != std::string::npos)
+ {
+ line.replace(pos, 1, "\\\"");
+ pos = line.find('\"', pos + 2);
+ }
+}
diff --git a/Source/CPack/cmCPackDragNDropGenerator.h b/Source/CPack/cmCPackDragNDropGenerator.h
index 1c84d49..da016f6 100644
--- a/Source/CPack/cmCPackDragNDropGenerator.h
+++ b/Source/CPack/cmCPackDragNDropGenerator.h
@@ -14,6 +14,7 @@
#define cmCPackDragNDropGenerator_h
#include "cmCPackGenerator.h"
+#include "cmGeneratedFileStream.h"
/** \class cmCPackDragNDropGenerator
* \brief A generator for OSX drag-n-drop installs
@@ -42,6 +43,15 @@ protected:
int CreateDMG(const std::string& src_dir, const std::string& output_file);
std::string InstallPrefix;
+
+private:
+ std::string slaDirectory;
+
+ void WriteLicense(cmGeneratedFileStream& outputStream, int licenseNumber,
+ std::string licenseLanguage, std::string licenseFile = "");
+ void BreakLongLine(const std::string& line,
+ std::vector<std::string>& lines);
+ void EscapeQuotes(std::string& line);
};
#endif
--
2.5.0
--
Powered by www.kitware.com
Please keep messages on-topic and check the CMake FAQ at:
http://www.cmake.org/Wiki/CMake_FAQ
Kitware offers various services to support the CMake community. For more
information on each offering, please visit:
CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html
Visit other Kitware open-source projects at
http://www.kitware.com/opensource/opensource.html
Follow this link to subscribe/unsubscribe:
http://public.kitware.com/mailman/listinfo/cmake-developers