114 lines
4.5 KiB
Java
Raw Normal View History

/*
Copyright 2019 Volker Berlin (i-net software)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package de.inetsoftware.jwebassembly.module;
import java.io.ByteArrayOutputStream;
2019-11-17 14:24:41 +01:00
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
2019-11-17 14:24:41 +01:00
import javax.annotation.Nonnegative;
/**
2019-11-17 14:24:41 +01:00
* Handle all the constant strings. The constant strings will be write into the data section.
*
* @author Volker Berlin
*/
class StringManager extends LinkedHashMap<String, Integer> {
/**
2019-11-17 14:24:41 +01:00
* Finish the prepare. Now no new strings should be added.
*
2019-11-17 14:24:41 +01:00
* @param writer
* the targets for the strings
* @throws IOException
* if any I/O error occur
*/
2019-11-17 14:24:41 +01:00
void prepareFinish( ModuleWriter writer ) throws IOException {
// inform the writer of string count that it can allocate a table of type anyref for the constant strings
writer.setStringCount( size() );
2019-11-17 14:24:41 +01:00
/* Write the strings to the data sections.
first there is a index table, then follows the strings
| ..... |
| start index string 1 (4 bytes) |
| start index string 2 (4 bytes) |
| start index string 3 (4 bytes) |
| ..... |
| length string 1 (1-x bytes) |
| string 1 (UTF8 encoded) |
| length string 2 (1-x bytes) |
| string 2 (UTF8 encoded) |
| ..... |
*/
ByteArrayOutputStream stringOut = new ByteArrayOutputStream();
ByteArrayOutputStream dataStream = writer.dataStream;
int offset = dataStream.size() + size() * 4;
for( String str : this.keySet() ) {
2019-11-17 14:24:41 +01:00
// write the position where the string starts in the data section
// little-endian byte order
int position = offset + stringOut.size();
dataStream.write( position >>> 0 );
dataStream.write( position >>> 8 );
dataStream.write( position >>> 16 );
dataStream.write( position >>> 24 );
byte[] bytes = str.getBytes( StandardCharsets.UTF_8 );
writeVaruint32( bytes.length, stringOut );
stringOut.write( bytes );
}
2019-11-17 14:24:41 +01:00
stringOut.writeTo( dataStream );
}
2019-11-17 14:24:41 +01:00
/**
* Write an unsigned integer.
*
* @param value
* the value
* @param out
* target stream
* @throws IOException
* if an I/O error occurs.
*/
private static void writeVaruint32( @Nonnegative int value, OutputStream out ) throws IOException {
if( value < 0 ) {
throw new IOException( "Invalid negative value" );
}
do {
int b = value & 0x7F; // low 7 bits
value >>= 7;
if( value != 0 ) { /* more bytes to come */
b |= 0x80;
}
out.write( b );
} while( value != 0 );
}
}