xoreos  0.0.5
nclr.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 /* Based heavily on the NCLR reader found in the NDS file viewer
26  * and editor Tinke by pleoNeX (<https://github.com/pleonex/tinke>),
27  * which is licensed under the terms of the GPLv3.
28  *
29  * Tinke in turn is based on the NCLR documentation by lowlines
30  * (<http://llref.emutalk.net/docs/?file=xml/nclr.xml>).
31  *
32  * The original copyright note in Tinke reads as follows:
33  *
34  * Copyright (C) 2011 pleoNeX
35  *
36  * This program is free software: you can redistribute it and/or modify
37  * it under the terms of the GNU General Public License as published by
38  * the Free Software Foundation, either version 3 of the License, or
39  * (at your option) any later version.
40  *
41  * This program is distributed in the hope that it will be useful,
42  * but WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44  * GNU General Public License for more details.
45  *
46  * You should have received a copy of the GNU General Public License
47  * along with this program. If not, see <http://www.gnu.org/licenses/>.
48  */
49 
50 #include <cstring>
51 
52 #include "src/common/scopedptr.h"
53 #include "src/common/util.h"
54 #include "src/common/strutil.h"
55 #include "src/common/readstream.h"
56 #include "src/common/error.h"
57 
59 
60 static const uint32 kNCLRID = MKTAG('N', 'C', 'L', 'R');
61 static const uint32 kPLTTID = MKTAG('P', 'L', 'T', 'T');
62 
63 namespace Graphics {
64 
68 
69  try {
70  nclrEndian.reset(open(nclr));
71  palette.reset(loadNCLR(*nclrEndian));
72 
73  } catch (Common::Exception &e) {
74  e.add("Failed reading NCLR file");
75  throw;
76  }
77 
78  return palette.release();
79 }
80 
82  readHeader(nclr);
83 
84  return readPalette(nclr);
85 }
86 
88  const uint32 tag = nclr.readUint32();
89  if (tag != kNCLRID)
90  throw Common::Exception("Invalid NCLR file (%s)", Common::debugTag(tag).c_str());
91 
92  const uint16 bom = nclr.readUint16();
93  if (bom != 0xFEFF)
94  throw Common::Exception("Invalid BOM: %u", bom);
95 
96  const uint8 versionMinor = nclr.readByte();
97  const uint8 versionMajor = nclr.readByte();
98  if ((versionMajor != 1) || (versionMinor != 0))
99  throw Common::Exception("Unsupported version %u.%u", versionMajor, versionMinor);
100 
101  const uint32 fileSize = nclr.readUint32();
102  if (fileSize > nclr.size())
103  throw Common::Exception("Size too large (%u > %u)", fileSize, (uint)nclr.size());
104 
105  const uint16 headerSize = nclr.readUint16();
106  if (headerSize != 16)
107  throw Common::Exception("Invalid header size (%u)", headerSize);
108 
109  const uint16 sectionCount = nclr.readUint16();
110  if ((sectionCount != 1) && (sectionCount != 2))
111  throw Common::Exception("Invalid number of sections (%u)", sectionCount);
112 }
113 
115  const uint32 tag = nclr.readUint32();
116  if (tag != kPLTTID)
117  throw Common::Exception("Invalid PLTT section (%s)", Common::debugTag(tag).c_str());
118 
119  const uint32 size = nclr.readUint32();
120 
121  const uint16 depthValue = nclr.readUint16();
122  if ((depthValue != 3) && (depthValue != 4))
123  throw Common::Exception("Invalid palette depth %u", depthValue);
124 
125  const uint8 depth = (depthValue == 3) ? 4 : 8;
126 
127  nclr.skip(6); // Unknown
128 
129  // Palette size. If not given or too big, calculate it from the section size
130  uint32 palSize = nclr.readUint32();
131  if ((palSize == 0) || (palSize > size))
132  palSize = size - 24;
133 
134  const uint32 startOffset = nclr.readUint32() + 24;
135 
136  // Clamp the number of colors to the actual palette size
137  const uint32 colorCount = MIN<uint32>(1 << depth, palSize / 2) * 3;
138 
139  nclr.seek(startOffset);
140 
141  Common::ScopedArray<byte> palette(new byte[colorCount * 3]);
142 
143  for (uint32 i = 0; i < colorCount; i += 3) {
144  const uint16 color = nclr.readUint16();
145 
146  palette[i + 0] = ((color >> 10) & 0x1F) << 3;
147  palette[i + 1] = ((color >> 5) & 0x1F) << 3;
148  palette[i + 2] = ( color & 0x1F) << 3;
149  }
150 
151  // Make the rest of the palette pink, for high debug visibility
152  static const byte kPink[3] = { 0xFF, 0x00, 0xFF };
153  for (uint32 i = colorCount; i < 768; i += sizeof(kPink))
154  std::memcpy(palette.get() + i, kPink, sizeof(kPink));
155 
156  return palette.release();
157 }
158 
159 } // End of namespace Graphics
Loading Nitro CoLoR palette files.
#define MKTAG(a0, a1, a2, a3)
A wrapper macro used around four character constants, like &#39;DATA&#39;, to ensure portability.
Definition: endianness.h:140
void add(const char *s,...) GCC_PRINTF(2
Definition: error.cpp:58
This is a wrapper around SeekableSubReadStream, but it adds non-endian read methods whose endianness ...
Definition: readstream.h:383
void reset(PointerType o=0)
Resets the pointer with the new value.
Definition: scopedptr.h:87
PointerType release()
Returns the plain pointer value and releases ScopedPtr.
Definition: scopedptr.h:103
uint8_t uint8
Definition: types.h:200
static const byte * load(Common::SeekableReadStream &nclr)
Definition: nclr.cpp:65
Utility templates and functions for working with strings and streams.
static const uint32 kPLTTID
Definition: nclr.cpp:61
Exception that provides a stack of explanations.
Definition: error.h:36
size_t size() const
Obtains the total size of the stream, measured in bytes.
Definition: readstream.cpp:144
static const byte * readPalette(Common::SeekableSubReadStreamEndian &nclr)
Definition: nclr.cpp:114
A simple scoped smart pointer template.
static const uint32 kNCLRID
Definition: nclr.cpp:60
Basic exceptions to throw.
size_t seek(ptrdiff_t offset, Origin whence=kOriginBegin)
Sets the stream position indicator for the stream.
Definition: readstream.cpp:148
uint16_t uint16
Definition: types.h:202
Utility templates and functions.
virtual size_t skip(ptrdiff_t offset)
Skip the specified number of bytes, adding that offset to the current position in the stream...
Definition: readstream.h:317
StackException Exception
Definition: error.h:59
Basic reading stream interfaces.
static const byte * loadNCLR(Common::SeekableSubReadStreamEndian &nclr)
Definition: nclr.cpp:81
PointerType get() const
Returns the plain pointer value.
Definition: scopedptr.h:96
uint32_t uint32
Definition: types.h:204
UString debugTag(uint32 tag, bool trim)
Create an elaborate string from an integer tag, for debugging purposes.
Definition: strutil.cpp:117
static Common::SeekableSubReadStreamEndian * open(Common::SeekableReadStream &stream)
Treat this stream as a Nitro file and return an endian&#39;d stream according to its BOM.
Definition: nitrofile.cpp:52
Interface for a seekable & readable data stream.
Definition: readstream.h:265
byte readByte()
Read an unsigned byte from the stream and return it.
Definition: readstream.h:92
uint8 byte
Definition: types.h:209
static void readHeader(Common::SeekableSubReadStreamEndian &nclr)
Definition: nclr.cpp:87
unsigned int uint
Definition: types.h:211